mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 08:31:59 +00:00
refactor(web): ConfirmDialog and dialogController (#9716)
* wrapper * no more callback * refactor: wip * refactor: wip * refactor: wip * pr feedback * fix * pr feedback
This commit is contained in:
parent
f020d29ab6
commit
bce916e4c8
26 changed files with 281 additions and 317 deletions
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { deleteUserAdmin, type UserResponseDto } from '@immich/sdk';
|
import { deleteUserAdmin, type UserResponseDto } from '@immich/sdk';
|
||||||
import { serverConfig } from '$lib/stores/server-config.store';
|
import { serverConfig } from '$lib/stores/server-config.store';
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="delete-user-confirmation-modal"
|
id="delete-user-confirmation-modal"
|
||||||
title="Delete user"
|
title="Delete user"
|
||||||
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
||||||
onConfirm={handleDeleteUser}
|
onConfirm={handleDeleteUser}
|
||||||
onClose={() => dispatch('cancel')}
|
onCancel={() => dispatch('cancel')}
|
||||||
disabled={deleteButtonDisabled}
|
disabled={deleteButtonDisabled}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="prompt">
|
<svelte:fragment slot="prompt">
|
||||||
|
@ -96,4 +96,4 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
mdiVideo,
|
mdiVideo,
|
||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
import type { ComponentType } from 'svelte';
|
import type { ComponentType } from 'svelte';
|
||||||
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
|
||||||
import JobTile from './job-tile.svelte';
|
import JobTile from './job-tile.svelte';
|
||||||
import StorageMigrationDescription from './storage-migration-description.svelte';
|
import StorageMigrationDescription from './storage-migration-description.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let jobs: AllJobStatusResponseDto;
|
export let jobs: AllJobStatusResponseDto;
|
||||||
|
|
||||||
|
@ -38,25 +38,24 @@
|
||||||
handleCommand?: (jobId: JobName, jobCommand: JobCommandDto) => Promise<void>;
|
handleCommand?: (jobId: JobName, jobCommand: JobCommandDto) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let confirmJob: JobName | null = null;
|
|
||||||
|
|
||||||
const handleConfirmCommand = async (jobId: JobName, dto: JobCommandDto) => {
|
const handleConfirmCommand = async (jobId: JobName, dto: JobCommandDto) => {
|
||||||
if (dto.force) {
|
if (dto.force) {
|
||||||
confirmJob = jobId;
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'confirm-reprocess-all-faces',
|
||||||
|
prompt: 'Are you sure you want to reprocess all faces? This will also clear named people.',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isConfirmed) {
|
||||||
|
await handleCommand(jobId, { command: JobCommand.Start, force: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await handleCommand(jobId, dto);
|
await handleCommand(jobId, dto);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onConfirm = async () => {
|
|
||||||
if (!confirmJob) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await handleCommand(confirmJob, { command: JobCommand.Start, force: true });
|
|
||||||
confirmJob = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
|
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
|
||||||
[JobName.ThumbnailGeneration]: {
|
[JobName.ThumbnailGeneration]: {
|
||||||
icon: mdiFileJpgBox,
|
icon: mdiFileJpgBox,
|
||||||
|
@ -152,15 +151,6 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if confirmJob}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="reprocess-faces-modal"
|
|
||||||
prompt="Are you sure you want to reprocess all faces? This will also clear named people."
|
|
||||||
{onConfirm}
|
|
||||||
onClose={() => (confirmJob = null)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-7">
|
<div class="flex flex-col gap-7">
|
||||||
{#each jobList as [jobName, { title, subtitle, disabled, allText, missingText, allowForceCommand, icon, component, handleCommand: handleCommandOverride }]}
|
{#each jobList as [jobName, { title, subtitle, disabled, allText, missingText, allowForceCommand, icon, component, handleCommand: handleCommandOverride }]}
|
||||||
{@const { jobCounts, queueStatus } = jobs[jobName]}
|
{@const { jobCounts, queueStatus } = jobs[jobName]}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { restoreUserAdmin, type UserResponseDto } from '@immich/sdk';
|
import { restoreUserAdmin, type UserResponseDto } from '@immich/sdk';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
@ -27,15 +27,15 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="restore-user-modal"
|
id="restore-user-modal"
|
||||||
title="Restore user"
|
title="Restore user"
|
||||||
confirmText="Continue"
|
confirmText="Continue"
|
||||||
confirmColor="green"
|
confirmColor="green"
|
||||||
onConfirm={handleRestoreUser}
|
onConfirm={handleRestoreUser}
|
||||||
onClose={() => dispatch('cancel')}
|
onCancel={() => dispatch('cancel')}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="prompt">
|
<svelte:fragment slot="prompt">
|
||||||
<p><b>{user.name}</b>'s account will be restored.</p>
|
<p><b>{user.name}</b>'s account will be restored.</p>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte';
|
||||||
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
||||||
import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
|
import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
|
||||||
import SettingInputField, {
|
import SettingInputField, {
|
||||||
|
@ -42,10 +42,10 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isConfirmOpen}
|
{#if isConfirmOpen}
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="disable-login-modal"
|
id="disable-login-modal"
|
||||||
title="Disable login"
|
title="Disable login"
|
||||||
onClose={() => (isConfirmOpen = false)}
|
onCancel={() => (isConfirmOpen = false)}
|
||||||
onConfirm={() => handleSave(true)}
|
onConfirm={() => handleSave(true)}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="prompt">
|
<svelte:fragment slot="prompt">
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js';
|
import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
|
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
NotificationType,
|
||||||
|
@ -33,6 +32,7 @@
|
||||||
} from '$lib/stores/preferences.store';
|
} from '$lib/stores/preferences.store';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let ownedAlbums: AlbumResponseDto[] = [];
|
export let ownedAlbums: AlbumResponseDto[] = [];
|
||||||
export let sharedAlbums: AlbumResponseDto[] = [];
|
export let sharedAlbums: AlbumResponseDto[] = [];
|
||||||
|
@ -275,9 +275,10 @@
|
||||||
sharedAlbums = sharedAlbums.filter(({ id }) => id !== albumToDelete.id);
|
sharedAlbums = sharedAlbums.filter(({ id }) => id !== albumToDelete.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAlbumToDelete = () => {
|
const setAlbumToDelete = async () => {
|
||||||
albumToDelete = contextMenuTargetAlbum ?? null;
|
albumToDelete = contextMenuTargetAlbum ?? null;
|
||||||
closeAlbumContextMenu();
|
closeAlbumContextMenu();
|
||||||
|
await deleteSelectedAlbum();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (album: AlbumResponseDto) => {
|
const handleEdit = (album: AlbumResponseDto) => {
|
||||||
|
@ -289,6 +290,16 @@
|
||||||
if (!albumToDelete) {
|
if (!albumToDelete) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'delete-album',
|
||||||
|
prompt: `Are you sure you want to delete the album ${albumToDelete.albumName}?\nIf this album is shared, other users will not be able to access it anymore.`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await handleDeleteAlbum(albumToDelete);
|
await handleDeleteAlbum(albumToDelete);
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -456,20 +467,4 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Delete Modal -->
|
|
||||||
{#if albumToDelete}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="delete-album-dialogue-modal"
|
|
||||||
title="Delete album"
|
|
||||||
confirmText="Delete"
|
|
||||||
onConfirm={deleteSelectedAlbum}
|
|
||||||
onClose={() => (albumToDelete = null)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>Are you sure you want to delete the album <b>{albumToDelete.albumName}</b>?</p>
|
|
||||||
<p>If this album is shared, other users will not be able to access it anymore.</p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
import { getContextMenuPosition } from '../../utils/context-menu';
|
import { getContextMenuPosition } from '../../utils/context-menu';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialog from '../shared-components/dialog/confirm-dialog.svelte';
|
||||||
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
|
@ -155,23 +155,23 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="leave-album-modal"
|
id="leave-album-modal"
|
||||||
title="Leave album?"
|
title="Leave album?"
|
||||||
prompt="Are you sure you want to leave {album.albumName}?"
|
prompt="Are you sure you want to leave {album.albumName}?"
|
||||||
confirmText="Leave"
|
confirmText="Leave"
|
||||||
onConfirm={handleRemoveUser}
|
onConfirm={handleRemoveUser}
|
||||||
onClose={() => (selectedRemoveUser = null)}
|
onCancel={() => (selectedRemoveUser = null)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="remove-user-modal"
|
id="remove-user-modal"
|
||||||
title="Remove user?"
|
title="Remove user?"
|
||||||
prompt="Are you sure you want to remove {selectedRemoveUser.name}?"
|
prompt="Are you sure you want to remove {selectedRemoveUser.name}?"
|
||||||
confirmText="Remove"
|
confirmText="Remove"
|
||||||
onConfirm={handleRemoveUser}
|
onConfirm={handleRemoveUser}
|
||||||
onClose={() => (selectedRemoveUser = null)}
|
onCancel={() => (selectedRemoveUser = null)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -12,17 +12,16 @@
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import FaceThumbnail from './face-thumbnail.svelte';
|
import FaceThumbnail from './face-thumbnail.svelte';
|
||||||
import PeopleList from './people-list.svelte';
|
import PeopleList from './people-list.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let person: PersonResponseDto;
|
export let person: PersonResponseDto;
|
||||||
let people: PersonResponseDto[] = [];
|
let people: PersonResponseDto[] = [];
|
||||||
let selectedPeople: PersonResponseDto[] = [];
|
let selectedPeople: PersonResponseDto[] = [];
|
||||||
let screenHeight: number;
|
let screenHeight: number;
|
||||||
let isShowConfirmation = false;
|
|
||||||
|
|
||||||
let dispatch = createEventDispatcher<{
|
let dispatch = createEventDispatcher<{
|
||||||
back: void;
|
back: void;
|
||||||
|
@ -65,6 +64,15 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMerge = async () => {
|
const handleMerge = async () => {
|
||||||
|
const isConfirm = await dialogController.show({
|
||||||
|
id: 'merge-people',
|
||||||
|
prompt: 'Do you want to merge these people?',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let results = await mergePerson({
|
let results = await mergePerson({
|
||||||
id: person.id,
|
id: person.id,
|
||||||
|
@ -79,8 +87,6 @@
|
||||||
dispatch('merge', mergedPerson);
|
dispatch('merge', mergedPerson);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Cannot merge people');
|
handleError(error, 'Cannot merge people');
|
||||||
} finally {
|
|
||||||
isShowConfirmation = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -101,13 +107,7 @@
|
||||||
<div />
|
<div />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="trailing">
|
<svelte:fragment slot="trailing">
|
||||||
<Button
|
<Button size={'sm'} disabled={!hasSelection} on:click={handleMerge}>
|
||||||
size={'sm'}
|
|
||||||
disabled={!hasSelection}
|
|
||||||
on:click={() => {
|
|
||||||
isShowConfirmation = true;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon path={mdiMerge} size={18} />
|
<Icon path={mdiMerge} size={18} />
|
||||||
<span class="ml-2"> Merge</span></Button
|
<span class="ml-2"> Merge</span></Button
|
||||||
>
|
>
|
||||||
|
@ -150,19 +150,5 @@
|
||||||
|
|
||||||
<PeopleList {people} {peopleToNotShow} {screenHeight} on:select={({ detail }) => onSelect(detail)} />
|
<PeopleList {people} {peopleToNotShow} {screenHeight} on:select={({ detail }) => onSelect(detail)} />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="merge-people-modal"
|
|
||||||
title="Merge people"
|
|
||||||
confirmText="Merge"
|
|
||||||
onConfirm={handleMerge}
|
|
||||||
onClose={() => (isShowConfirmation = false)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>Are you sure you want merge these people ?</p></svelte:fragment
|
|
||||||
>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { serverInfo } from '$lib/stores/server-info.store';
|
import { serverInfo } from '$lib/stores/server-info.store';
|
||||||
|
@ -9,6 +8,7 @@
|
||||||
import { mdiAccountEditOutline } from '@mdi/js';
|
import { mdiAccountEditOutline } from '@mdi/js';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let user: UserAdminResponseDto;
|
export let user: UserAdminResponseDto;
|
||||||
export let canResetPassword = true;
|
export let canResetPassword = true;
|
||||||
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
let error: string;
|
let error: string;
|
||||||
let success: string;
|
let success: string;
|
||||||
let isShowResetPasswordConfirmation = false;
|
|
||||||
let quotaSize = user.quotaSizeInBytes ? convertFromBytes(user.quotaSizeInBytes, 'GiB') : null;
|
let quotaSize = user.quotaSizeInBytes ? convertFromBytes(user.quotaSizeInBytes, 'GiB') : null;
|
||||||
|
|
||||||
const previousQutoa = user.quotaSizeInBytes;
|
const previousQutoa = user.quotaSizeInBytes;
|
||||||
|
@ -53,6 +52,15 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetPassword = async () => {
|
const resetPassword = async () => {
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'confirm-reset-password',
|
||||||
|
prompt: `Are you sure you want to reset ${user.name}'s password?`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newPassword = generatePassword();
|
newPassword = generatePassword();
|
||||||
|
|
||||||
|
@ -67,8 +75,6 @@
|
||||||
dispatch('resetPasswordSuccess');
|
dispatch('resetPasswordSuccess');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Unable to reset password');
|
handleError(error, 'Unable to reset password');
|
||||||
} finally {
|
|
||||||
isShowResetPasswordConfirmation = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,26 +146,8 @@
|
||||||
</form>
|
</form>
|
||||||
<svelte:fragment slot="sticky-bottom">
|
<svelte:fragment slot="sticky-bottom">
|
||||||
{#if canResetPassword}
|
{#if canResetPassword}
|
||||||
<Button color="light-red" fullwidth on:click={() => (isShowResetPasswordConfirmation = true)}
|
<Button color="light-red" fullwidth on:click={resetPassword}>Reset password</Button>
|
||||||
>Reset password</Button
|
|
||||||
>
|
|
||||||
{/if}
|
{/if}
|
||||||
<Button type="submit" fullwidth form="edit-user-form">Confirm</Button>
|
<Button type="submit" fullwidth form="edit-user-form">Confirm</Button>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
||||||
{#if isShowResetPasswordConfirmation}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="reset-password-modal"
|
|
||||||
title="Reset password"
|
|
||||||
confirmText="Reset"
|
|
||||||
onConfirm={resetPassword}
|
|
||||||
onClose={() => (isShowResetPasswordConfirmation = false)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>
|
|
||||||
Are you sure you want to reset <b>{user.name}</b>'s password?
|
|
||||||
</p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
NotificationType,
|
||||||
notificationController,
|
notificationController,
|
||||||
|
@ -10,6 +9,7 @@
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
import { s } from '$lib/utils';
|
import { s } from '$lib/utils';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
export let onRemove: ((assetIds: string[]) => void) | undefined;
|
export let onRemove: ((assetIds: string[]) => void) | undefined;
|
||||||
|
@ -17,9 +17,16 @@
|
||||||
|
|
||||||
const { getAssets, clearSelect } = getAssetControlContext();
|
const { getAssets, clearSelect } = getAssetControlContext();
|
||||||
|
|
||||||
let isShowConfirmation = false;
|
|
||||||
|
|
||||||
const removeFromAlbum = async () => {
|
const removeFromAlbum = async () => {
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'remove-from-album',
|
||||||
|
prompt: `Are you sure you want to remove ${getAssets().size} asset${s(getAssets().size)} from the album?`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ids = [...getAssets()].map((a) => a.id);
|
const ids = [...getAssets()].map((a) => a.id);
|
||||||
const results = await removeAssetFromAlbum({
|
const results = await removeAssetFromAlbum({
|
||||||
|
@ -44,36 +51,12 @@
|
||||||
type: NotificationType.Error,
|
type: NotificationType.Error,
|
||||||
message: 'Error removing assets from album, check console for more details',
|
message: 'Error removing assets from album, check console for more details',
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
isShowConfirmation = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text="Remove from album" icon={mdiImageRemoveOutline} on:click={() => (isShowConfirmation = true)} />
|
<MenuOption text="Remove from album" icon={mdiImageRemoveOutline} on:click={removeFromAlbum} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title="Remove from album" icon={mdiDeleteOutline} on:click={() => (isShowConfirmation = true)} />
|
<CircleIconButton title="Remove from album" icon={mdiDeleteOutline} on:click={removeFromAlbum} />
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="remove-from-album-modal"
|
|
||||||
title="Remove from {album.albumName}"
|
|
||||||
confirmText="Remove"
|
|
||||||
onConfirm={removeFromAlbum}
|
|
||||||
onClose={() => (isShowConfirmation = false)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>
|
|
||||||
Are you sure you want to remove
|
|
||||||
{#if getAssets().size > 1}
|
|
||||||
these <b>{getAssets().size}</b> assets
|
|
||||||
{:else}
|
|
||||||
this asset
|
|
||||||
{/if}
|
|
||||||
from the album?
|
|
||||||
</p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { getKey } from '$lib/utils';
|
import { getKey, s } from '$lib/utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { removeSharedLinkAssets, type SharedLinkResponseDto } from '@immich/sdk';
|
import { removeSharedLinkAssets, type SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { mdiDeleteOutline } from '@mdi/js';
|
import { mdiDeleteOutline } from '@mdi/js';
|
||||||
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
|
||||||
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let sharedLink: SharedLinkResponseDto;
|
export let sharedLink: SharedLinkResponseDto;
|
||||||
|
|
||||||
let removing = false;
|
|
||||||
|
|
||||||
const { getAssets, clearSelect } = getAssetControlContext();
|
const { getAssets, clearSelect } = getAssetControlContext();
|
||||||
|
|
||||||
const handleRemove = async () => {
|
const handleRemove = async () => {
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'remove-from-shared-link',
|
||||||
|
title: 'Remove assets?',
|
||||||
|
prompt: `Are you sure you want to remove ${getAssets().size} asset${s(getAssets().size)} from this shared link?`,
|
||||||
|
confirmText: 'Remove',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await removeSharedLinkAssets({
|
const results = await removeSharedLinkAssets({
|
||||||
id: sharedLink.id,
|
id: sharedLink.id,
|
||||||
|
@ -46,15 +55,4 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton title="Remove from shared link" on:click={() => (removing = true)} icon={mdiDeleteOutline} />
|
<CircleIconButton title="Remove from shared link" on:click={handleRemove} icon={mdiDeleteOutline} />
|
||||||
|
|
||||||
{#if removing}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="remove-assets-modal"
|
|
||||||
title="Remove assets?"
|
|
||||||
prompt="Are you sure you want to remove {getAssets().size} asset(s) from this shared link?"
|
|
||||||
confirmText="Remove"
|
|
||||||
onConfirm={() => handleRemove()}
|
|
||||||
onClose={() => (removing = false)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialog from '../shared-components/dialog/confirm-dialog.svelte';
|
||||||
import { showDeleteModal } from '$lib/stores/preferences.store';
|
import { showDeleteModal } from '$lib/stores/preferences.store';
|
||||||
import Checkbox from '$lib/components/elements/checkbox.svelte';
|
import Checkbox from '$lib/components/elements/checkbox.svelte';
|
||||||
import { s } from '$lib/utils';
|
import { s } from '$lib/utils';
|
||||||
|
@ -22,12 +22,12 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="permanently-delete-asset-modal"
|
id="permanently-delete-asset-modal"
|
||||||
title="Permanently delete asset{s(size)}"
|
title="Permanently delete asset{s(size)}"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={() => dispatch('cancel')}
|
onCancel={() => dispatch('cancel')}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="prompt">
|
<svelte:fragment slot="prompt">
|
||||||
<p>
|
<p>
|
||||||
|
@ -44,4 +44,4 @@
|
||||||
<Checkbox id="confirm-deletion-input" label="Do not show this message again" bind:checked />
|
<Checkbox id="confirm-deletion-input" label="Do not show this message again" bind:checked />
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import ConfirmDialogue from './confirm-dialogue.svelte';
|
import ConfirmDialog from './dialog/confirm-dialog.svelte';
|
||||||
import Combobox from './combobox.svelte';
|
import Combobox from './combobox.svelte';
|
||||||
import DateInput from '../elements/date-input.svelte';
|
import DateInput from '../elements/date-input.svelte';
|
||||||
|
|
||||||
|
@ -55,14 +55,14 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="edit-date-time-modal"
|
id="edit-date-time-modal"
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
title="Edit date and time"
|
title="Edit date and time"
|
||||||
prompt="Please select a new date:"
|
prompt="Please select a new date:"
|
||||||
disabled={!date.isValid}
|
disabled={!date.isValid}
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={handleCancel}
|
onCancel={handleCancel}
|
||||||
>
|
>
|
||||||
<div class="flex flex-col text-md px-4 text-center gap-2" slot="prompt">
|
<div class="flex flex-col text-md px-4 text-center gap-2" slot="prompt">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
@ -84,4 +84,4 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import ConfirmDialogue from './confirm-dialogue.svelte';
|
import ConfirmDialog from './dialog/confirm-dialog.svelte';
|
||||||
import { timeDebounceOnSearch } from '$lib/constants';
|
import { timeDebounceOnSearch } from '$lib/constants';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
|
||||||
|
@ -103,13 +103,13 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="change-location-modal"
|
id="change-location-modal"
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
title="Change location"
|
title="Change location"
|
||||||
width="wide"
|
width="wide"
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={handleCancel}
|
onCancel={handleCancel}
|
||||||
>
|
>
|
||||||
<div slot="prompt" class="flex flex-col w-full h-full gap-2">
|
<div slot="prompt" class="flex flex-col w-full h-full gap-2">
|
||||||
<div
|
<div
|
||||||
|
@ -182,4 +182,4 @@
|
||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import FullScreenModal from './full-screen-modal.svelte';
|
import FullScreenModal from '../full-screen-modal.svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../../elements/buttons/button.svelte';
|
||||||
import type { Color } from '$lib/components/elements/buttons/button.svelte';
|
import type { Color } from '$lib/components/elements/buttons/button.svelte';
|
||||||
|
|
||||||
export let id: string;
|
export let id: string = 'confirm-dialog';
|
||||||
export let title = 'Confirm';
|
export let title = 'Confirm';
|
||||||
export let prompt = 'Are you sure you want to do this?';
|
export let prompt = 'Are you sure you want to do this?';
|
||||||
export let confirmText = 'Confirm';
|
export let confirmText = 'Confirm';
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
export let hideCancelButton = false;
|
export let hideCancelButton = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let width: 'wide' | 'narrow' = 'narrow';
|
export let width: 'wide' | 'narrow' = 'narrow';
|
||||||
export let onClose: () => void;
|
export let onCancel: () => void;
|
||||||
export let onConfirm: () => void;
|
export let onConfirm: () => void;
|
||||||
|
|
||||||
let isConfirmButtonDisabled = false;
|
let isConfirmButtonDisabled = false;
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal {title} {id} {onClose} {width}>
|
<FullScreenModal {title} {id} onClose={onCancel} {width}>
|
||||||
<div class="text-md py-5 text-center">
|
<div class="text-md py-5 text-center">
|
||||||
<slot name="prompt">
|
<slot name="prompt">
|
||||||
<p>{prompt}</p>
|
<p>{prompt}</p>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<svelte:fragment slot="sticky-bottom">
|
<svelte:fragment slot="sticky-bottom">
|
||||||
{#if !hideCancelButton}
|
{#if !hideCancelButton}
|
||||||
<Button color={cancelColor} fullwidth on:click={onClose}>
|
<Button color={cancelColor} fullwidth on:click={onCancel}>
|
||||||
{cancelText}
|
{cancelText}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { dialogController } from './dialog';
|
||||||
|
import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte';
|
||||||
|
const { dialog } = dialogController;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $dialog}
|
||||||
|
<ConfirmDialog {...$dialog} />
|
||||||
|
{/if}
|
48
web/src/lib/components/shared-components/dialog/dialog.ts
Normal file
48
web/src/lib/components/shared-components/dialog/dialog.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
type DialogActions = {
|
||||||
|
onConfirm: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DialogOptions = {
|
||||||
|
id?: string;
|
||||||
|
title?: string;
|
||||||
|
prompt?: string;
|
||||||
|
confirmText?: string;
|
||||||
|
cancelText?: string;
|
||||||
|
hideCancelButton?: boolean;
|
||||||
|
disable?: boolean;
|
||||||
|
width?: 'wide' | 'narrow' | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Dialog = DialogOptions & DialogActions;
|
||||||
|
|
||||||
|
function createDialogWrapper() {
|
||||||
|
const dialog = writable<Dialog | undefined>();
|
||||||
|
|
||||||
|
async function show(options: DialogOptions) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const newDialog: Dialog = {
|
||||||
|
...options,
|
||||||
|
onConfirm: () => {
|
||||||
|
dialog.set(undefined);
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
dialog.set(undefined);
|
||||||
|
resolve(false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog.set(newDialog);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dialog,
|
||||||
|
show,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dialogController = createDialogWrapper();
|
|
@ -47,7 +47,7 @@
|
||||||
role="presentation"
|
role="presentation"
|
||||||
in:fade={{ duration: 100 }}
|
in:fade={{ duration: 100 }}
|
||||||
out:fade={{ duration: 100 }}
|
out:fade={{ duration: 100 }}
|
||||||
class="fixed left-0 top-0 z-[9990] flex h-screen w-screen place-content-center place-items-center bg-black/40"
|
class="fixed left-0 top-0 z-[9999] flex h-screen w-screen place-content-center place-items-center bg-black/40"
|
||||||
on:keydown={(event) => {
|
on:keydown={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -2,36 +2,47 @@
|
||||||
import { deleteAllSessions, deleteSession, getSessions, type SessionResponseDto } from '@immich/sdk';
|
import { deleteAllSessions, deleteSession, getSessions, type SessionResponseDto } from '@immich/sdk';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
|
||||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||||
import DeviceCard from './device-card.svelte';
|
import DeviceCard from './device-card.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let devices: SessionResponseDto[];
|
export let devices: SessionResponseDto[];
|
||||||
let deleteDevice: SessionResponseDto | null = null;
|
|
||||||
let deleteAll = false;
|
|
||||||
|
|
||||||
const refresh = () => getSessions().then((_devices) => (devices = _devices));
|
const refresh = () => getSessions().then((_devices) => (devices = _devices));
|
||||||
|
|
||||||
$: currentDevice = devices.find((device) => device.current);
|
$: currentDevice = devices.find((device) => device.current);
|
||||||
$: otherDevices = devices.filter((device) => !device.current);
|
$: otherDevices = devices.filter((device) => !device.current);
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (device: SessionResponseDto) => {
|
||||||
if (!deleteDevice) {
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'log-out-device',
|
||||||
|
prompt: 'Are you sure you want to log out this device?',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteSession({ id: deleteDevice.id });
|
await deleteSession({ id: device.id });
|
||||||
notificationController.show({ message: `Logged out device`, type: NotificationType.Info });
|
notificationController.show({ message: `Logged out device`, type: NotificationType.Info });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Unable to log out device');
|
handleError(error, 'Unable to log out device');
|
||||||
} finally {
|
} finally {
|
||||||
await refresh();
|
await refresh();
|
||||||
deleteDevice = null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAll = async () => {
|
const handleDeleteAll = async () => {
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'log-out-all-devices',
|
||||||
|
prompt: 'Are you sure you want to log out all devices?',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteAllSessions();
|
await deleteAllSessions();
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
|
@ -42,29 +53,10 @@
|
||||||
handleError(error, 'Unable to log out all devices');
|
handleError(error, 'Unable to log out all devices');
|
||||||
} finally {
|
} finally {
|
||||||
await refresh();
|
await refresh();
|
||||||
deleteAll = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if deleteDevice}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="log-out-device-modal"
|
|
||||||
prompt="Are you sure you want to log out this device?"
|
|
||||||
onConfirm={() => handleDelete()}
|
|
||||||
onClose={() => (deleteDevice = null)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if deleteAll}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="log-out-all-modal"
|
|
||||||
prompt="Are you sure you want to log out all devices?"
|
|
||||||
onConfirm={() => handleDeleteAll()}
|
|
||||||
onClose={() => (deleteAll = false)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section class="my-4">
|
<section class="my-4">
|
||||||
{#if currentDevice}
|
{#if currentDevice}
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
|
@ -76,7 +68,7 @@
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary">OTHER DEVICES</h3>
|
<h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary">OTHER DEVICES</h3>
|
||||||
{#each otherDevices as device, index}
|
{#each otherDevices as device, index}
|
||||||
<DeviceCard {device} on:delete={() => (deleteDevice = device)} />
|
<DeviceCard {device} on:delete={() => handleDelete(device)} />
|
||||||
{#if index !== otherDevices.length - 1}
|
{#if index !== otherDevices.length - 1}
|
||||||
<hr class="my-3" />
|
<hr class="my-3" />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -84,7 +76,7 @@
|
||||||
</div>
|
</div>
|
||||||
<h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary">LOG OUT ALL DEVICES</h3>
|
<h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary">LOG OUT ALL DEVICES</h3>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<Button color="red" size="sm" on:click={() => (deleteAll = true)}>Log Out All Devices</Button>
|
<Button color="red" size="sm" on:click={handleDeleteAll}>Log Out All Devices</Button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import Icon from '../elements/icon.svelte';
|
import Icon from '../elements/icon.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||||
import PartnerSelectionModal from './partner-selection-modal.svelte';
|
import PartnerSelectionModal from './partner-selection-modal.svelte';
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
interface PartnerSharing {
|
interface PartnerSharing {
|
||||||
user: UserResponseDto;
|
user: UserResponseDto;
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
|
|
||||||
let createPartnerFlag = false;
|
let createPartnerFlag = false;
|
||||||
let removePartnerDto: PartnerResponseDto | null = null;
|
// let removePartnerDto: PartnerResponseDto | null = null;
|
||||||
let partners: Array<PartnerSharing> = [];
|
let partners: Array<PartnerSharing> = [];
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
@ -75,14 +75,19 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemovePartner = async () => {
|
const handleRemovePartner = async (partner: PartnerResponseDto) => {
|
||||||
if (!removePartnerDto) {
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'remove-partner',
|
||||||
|
title: 'Stop sharing your photos?',
|
||||||
|
prompt: `${partner.name} will no longer be able to access your photos.`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await removePartner({ id: removePartnerDto.id });
|
await removePartner({ id: partner.id });
|
||||||
removePartnerDto = null;
|
|
||||||
await refreshPartners();
|
await refreshPartners();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Unable to remove partner');
|
handleError(error, 'Unable to remove partner');
|
||||||
|
@ -133,7 +138,7 @@
|
||||||
|
|
||||||
{#if partner.sharedByMe}
|
{#if partner.sharedByMe}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
on:click={() => (removePartnerDto = partner.user)}
|
on:click={() => handleRemovePartner(partner.user)}
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
size={'16'}
|
size={'16'}
|
||||||
title="Stop sharing your photos with this user"
|
title="Stop sharing your photos with this user"
|
||||||
|
@ -186,13 +191,3 @@
|
||||||
on:add-users={(event) => handleCreatePartners(event.detail)}
|
on:add-users={(event) => handleCreatePartners(event.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if removePartnerDto}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="stop-sharing-photos-modal"
|
|
||||||
title="Stop sharing your photos?"
|
|
||||||
prompt="{removePartnerDto.name} will no longer be able to access your photos."
|
|
||||||
onClose={() => (removePartnerDto = null)}
|
|
||||||
onConfirm={() => handleRemovePartner()}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -7,15 +7,14 @@
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import APIKeyForm from '../forms/api-key-form.svelte';
|
import APIKeyForm from '../forms/api-key-form.svelte';
|
||||||
import APIKeySecret from '../forms/api-key-secret.svelte';
|
import APIKeySecret from '../forms/api-key-secret.svelte';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let keys: ApiKeyResponseDto[];
|
export let keys: ApiKeyResponseDto[];
|
||||||
|
|
||||||
let newKey: Partial<ApiKeyResponseDto> | null = null;
|
let newKey: Partial<ApiKeyResponseDto> | null = null;
|
||||||
let editKey: ApiKeyResponseDto | null = null;
|
let editKey: ApiKeyResponseDto | null = null;
|
||||||
let deleteKey: ApiKeyResponseDto | null = null;
|
|
||||||
let secret = '';
|
let secret = '';
|
||||||
|
|
||||||
const format: Intl.DateTimeFormatOptions = {
|
const format: Intl.DateTimeFormatOptions = {
|
||||||
|
@ -59,22 +58,26 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (key: ApiKeyResponseDto) => {
|
||||||
if (!deleteKey) {
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'delete-api-key',
|
||||||
|
prompt: 'Are you sure you want to delete this API key?',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteApiKey({ id: deleteKey.id });
|
await deleteApiKey({ id: key.id });
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
message: `Removed API Key: ${deleteKey.name}`,
|
message: `Removed API Key: ${key.name}`,
|
||||||
type: NotificationType.Info,
|
type: NotificationType.Info,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Unable to remove API Key');
|
handleError(error, 'Unable to remove API Key');
|
||||||
} finally {
|
} finally {
|
||||||
await refreshKeys();
|
await refreshKeys();
|
||||||
deleteKey = null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -103,15 +106,6 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if deleteKey}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="confirm-api-key-delete-modal"
|
|
||||||
prompt="Are you sure you want to delete this API key?"
|
|
||||||
onConfirm={() => handleDelete()}
|
|
||||||
onClose={() => (deleteKey = null)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section class="my-4">
|
<section class="my-4">
|
||||||
<div class="flex flex-col gap-2" in:fade={{ duration: 500 }}>
|
<div class="flex flex-col gap-2" in:fade={{ duration: 500 }}>
|
||||||
<div class="mb-2 flex justify-end">
|
<div class="mb-2 flex justify-end">
|
||||||
|
@ -156,7 +150,7 @@
|
||||||
icon={mdiTrashCanOutline}
|
icon={mdiTrashCanOutline}
|
||||||
title="Delete key"
|
title="Delete key"
|
||||||
size="16"
|
size="16"
|
||||||
on:click={() => (deleteKey = key)}
|
on:click={() => handleDelete(key)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
|
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
|
||||||
import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte';
|
import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte';
|
||||||
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
|
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
|
@ -81,6 +80,7 @@
|
||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
@ -98,7 +98,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ViewMode {
|
enum ViewMode {
|
||||||
CONFIRM_DELETE = 'confirm-delete',
|
|
||||||
LINK_SHARING = 'link-sharing',
|
LINK_SHARING = 'link-sharing',
|
||||||
SELECT_USERS = 'select-users',
|
SELECT_USERS = 'select-users',
|
||||||
SELECT_THUMBNAIL = 'select-thumbnail',
|
SELECT_THUMBNAIL = 'select-thumbnail',
|
||||||
|
@ -248,10 +247,7 @@
|
||||||
viewMode = ViewMode.VIEW;
|
viewMode = ViewMode.VIEW;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (viewMode === ViewMode.CONFIRM_DELETE) {
|
|
||||||
viewMode = ViewMode.VIEW;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (viewMode === ViewMode.SELECT_ASSETS) {
|
if (viewMode === ViewMode.SELECT_ASSETS) {
|
||||||
handleCloseSelectAssets();
|
handleCloseSelectAssets();
|
||||||
return;
|
return;
|
||||||
|
@ -353,6 +349,16 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveAlbum = async () => {
|
const handleRemoveAlbum = async () => {
|
||||||
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'remove-album',
|
||||||
|
prompt: `Are you sure you want to delete the album ${album.albumName}?\nIf this album is shared, other users will not be able to access it anymore.`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
viewMode = ViewMode.VIEW;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteAlbum({ id: album.id });
|
await deleteAlbum({ id: album.id });
|
||||||
await goto(backUrl);
|
await goto(backUrl);
|
||||||
|
@ -471,11 +477,7 @@
|
||||||
on:click={() => (viewMode = ViewMode.SELECT_THUMBNAIL)}
|
on:click={() => (viewMode = ViewMode.SELECT_THUMBNAIL)}
|
||||||
/>
|
/>
|
||||||
<MenuOption icon={mdiCogOutline} text="Options" on:click={() => (viewMode = ViewMode.OPTIONS)} />
|
<MenuOption icon={mdiCogOutline} text="Options" on:click={() => (viewMode = ViewMode.OPTIONS)} />
|
||||||
<MenuOption
|
<MenuOption icon={mdiDeleteOutline} text="Delete album" on:click={() => handleRemoveAlbum()} />
|
||||||
icon={mdiDeleteOutline}
|
|
||||||
text="Delete album"
|
|
||||||
on:click={() => (viewMode = ViewMode.CONFIRM_DELETE)}
|
|
||||||
/>
|
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -697,21 +699,6 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if viewMode === ViewMode.CONFIRM_DELETE}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="delete-album-modal"
|
|
||||||
title="Delete album"
|
|
||||||
confirmText="Delete"
|
|
||||||
onConfirm={handleRemoveAlbum}
|
|
||||||
onClose={() => (viewMode = ViewMode.VIEW)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>Are you sure you want to delete the album <b>{album.albumName}</b>?</p>
|
|
||||||
<p>If this album is shared, other users will not be able to access it anymore.</p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if viewMode === ViewMode.OPTIONS && $user}
|
{#if viewMode === ViewMode.OPTIONS && $user}
|
||||||
<AlbumOptions
|
<AlbumOptions
|
||||||
{album}
|
{album}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
||||||
import {
|
import {
|
||||||
|
@ -15,12 +15,11 @@
|
||||||
import { getAllSharedLinks, removeSharedLink, type SharedLinkResponseDto } from '@immich/sdk';
|
import { getAllSharedLinks, removeSharedLink, type SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { mdiArrowLeft } from '@mdi/js';
|
import { mdiArrowLeft } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
let sharedLinks: SharedLinkResponseDto[] = [];
|
let sharedLinks: SharedLinkResponseDto[] = [];
|
||||||
let editSharedLink: SharedLinkResponseDto | null = null;
|
let editSharedLink: SharedLinkResponseDto | null = null;
|
||||||
|
|
||||||
let deleteLinkId: string | null = null;
|
|
||||||
|
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
sharedLinks = await getAllSharedLinks();
|
sharedLinks = await getAllSharedLinks();
|
||||||
};
|
};
|
||||||
|
@ -29,15 +28,21 @@
|
||||||
await refresh();
|
await refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleDeleteLink = async () => {
|
const handleDeleteLink = async (id: string) => {
|
||||||
if (!deleteLinkId) {
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'delete-shared-link',
|
||||||
|
title: 'Delete shared link',
|
||||||
|
prompt: 'Are you sure you want to delete this shared link?',
|
||||||
|
confirmText: 'Delete',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await removeSharedLink({ id: deleteLinkId });
|
await removeSharedLink({ id });
|
||||||
notificationController.show({ message: 'Deleted shared link', type: NotificationType.Info });
|
notificationController.show({ message: 'Deleted shared link', type: NotificationType.Info });
|
||||||
deleteLinkId = null;
|
|
||||||
await refresh();
|
await refresh();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, 'Unable to delete shared link');
|
handleError(error, 'Unable to delete shared link');
|
||||||
|
@ -73,7 +78,7 @@
|
||||||
{#each sharedLinks as link (link.id)}
|
{#each sharedLinks as link (link.id)}
|
||||||
<SharedLinkCard
|
<SharedLinkCard
|
||||||
{link}
|
{link}
|
||||||
on:delete={() => (deleteLinkId = link.id)}
|
on:delete={() => handleDeleteLink(link.id)}
|
||||||
on:edit={() => (editSharedLink = link)}
|
on:edit={() => (editSharedLink = link)}
|
||||||
on:copy={() => handleCopyLink(link.key)}
|
on:copy={() => handleCopyLink(link.key)}
|
||||||
/>
|
/>
|
||||||
|
@ -85,14 +90,3 @@
|
||||||
{#if editSharedLink}
|
{#if editSharedLink}
|
||||||
<CreateSharedLinkModal editingLink={editSharedLink} onClose={handleEditDone} />
|
<CreateSharedLinkModal editingLink={editSharedLink} onClose={handleEditDone} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if deleteLinkId}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="delete-shared-link-modal"
|
|
||||||
title="Delete shared link"
|
|
||||||
prompt="Are you sure you want to delete this shared link?"
|
|
||||||
confirmText="Delete"
|
|
||||||
onConfirm={() => handleDeleteLink()}
|
|
||||||
onClose={() => (deleteLinkId = null)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
|
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
|
||||||
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
|
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
|
||||||
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
|
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
NotificationType,
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
import { mdiDeleteOutline, mdiHistory } from '@mdi/js';
|
import { mdiDeleteOutline, mdiHistory } from '@mdi/js';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { handlePromiseError } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
@ -32,10 +32,18 @@
|
||||||
const assetStore = new AssetStore({ isTrashed: true });
|
const assetStore = new AssetStore({ isTrashed: true });
|
||||||
const assetInteractionStore = createAssetInteractionStore();
|
const assetInteractionStore = createAssetInteractionStore();
|
||||||
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
||||||
let isShowEmptyConfirmation = false;
|
|
||||||
|
|
||||||
const handleEmptyTrash = async () => {
|
const handleEmptyTrash = async () => {
|
||||||
isShowEmptyConfirmation = false;
|
const isConfirmed = await dialogController.show({
|
||||||
|
id: 'empty-trash',
|
||||||
|
prompt:
|
||||||
|
'Are you sure you want to empty the trash? This will remove all the assets in trash permanently from Immich.\nYou cannot undo this action!',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await emptyTrash();
|
await emptyTrash();
|
||||||
|
|
||||||
|
@ -87,7 +95,7 @@
|
||||||
Restore all
|
Restore all
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => (isShowEmptyConfirmation = true)}>
|
<LinkButton on:click={() => handleEmptyTrash()}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Icon path={mdiDeleteOutline} size="18" />
|
<Icon path={mdiDeleteOutline} size="18" />
|
||||||
Empty trash
|
Empty trash
|
||||||
|
@ -103,18 +111,3 @@
|
||||||
</AssetGrid>
|
</AssetGrid>
|
||||||
</UserPageLayout>
|
</UserPageLayout>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isShowEmptyConfirmation}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="empty-trash-modal"
|
|
||||||
title="Empty trash"
|
|
||||||
confirmText="Empty"
|
|
||||||
onConfirm={handleEmptyTrash}
|
|
||||||
onClose={() => (isShowEmptyConfirmation = false)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<p>Are you sure you want to empty the trash? This will remove all the assets in trash permanently from Immich.</p>
|
|
||||||
<p><b>You cannot undo this action!</b></p>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
import { isAssetViewerRoute, isSharedLinkRoute } from '$lib/utils/navigation';
|
import { isAssetViewerRoute, isSharedLinkRoute } from '$lib/utils/navigation';
|
||||||
|
import DialogWrapper from '$lib/components/shared-components/dialog/dialog-wrapper.svelte';
|
||||||
|
|
||||||
let showNavigationLoadingBar = false;
|
let showNavigationLoadingBar = false;
|
||||||
|
|
||||||
|
@ -121,6 +122,7 @@
|
||||||
<DownloadPanel />
|
<DownloadPanel />
|
||||||
<UploadPanel />
|
<UploadPanel />
|
||||||
<NotificationList />
|
<NotificationList />
|
||||||
|
<DialogWrapper />
|
||||||
|
|
||||||
{#if $user?.isAdmin}
|
{#if $user?.isAdmin}
|
||||||
<VersionAnnouncementBox />
|
<VersionAnnouncementBox />
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import LibraryScanSettingsForm from '$lib/components/forms/library-scan-settings-form.svelte';
|
import LibraryScanSettingsForm from '$lib/components/forms/library-scan-settings-form.svelte';
|
||||||
import LibraryUserPickerForm from '$lib/components/forms/library-user-picker-form.svelte';
|
import LibraryUserPickerForm from '$lib/components/forms/library-user-picker-form.svelte';
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
|
@ -37,6 +36,7 @@
|
||||||
import LinkButton from '../../../lib/components/elements/buttons/link-button.svelte';
|
import LinkButton from '../../../lib/components/elements/buttons/link-button.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
@ -282,29 +282,39 @@
|
||||||
const onDeleteLibraryClicked = async () => {
|
const onDeleteLibraryClicked = async () => {
|
||||||
closeAll();
|
closeAll();
|
||||||
|
|
||||||
if (selectedLibrary && confirm(`Are you sure you want to delete ${selectedLibrary.name} library?`) == true) {
|
if (!selectedLibrary) {
|
||||||
await refreshStats(selectedLibraryIndex);
|
return;
|
||||||
if (totalCount[selectedLibraryIndex] > 0) {
|
}
|
||||||
deleteAssetCount = totalCount[selectedLibraryIndex];
|
|
||||||
confirmDeleteLibrary = selectedLibrary;
|
const isConfirmedLibrary = await dialogController.show({
|
||||||
} else {
|
id: 'delete-library',
|
||||||
deletedLibrary = selectedLibrary;
|
prompt: `Are you sure you want to delete ${selectedLibrary.name} library?`,
|
||||||
await handleDelete();
|
});
|
||||||
|
|
||||||
|
if (!isConfirmedLibrary) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await refreshStats(selectedLibraryIndex);
|
||||||
|
if (totalCount[selectedLibraryIndex] > 0) {
|
||||||
|
deleteAssetCount = totalCount[selectedLibraryIndex];
|
||||||
|
|
||||||
|
const isConfirmedLibraryAssetCount = await dialogController.show({
|
||||||
|
id: 'delete-library-assets',
|
||||||
|
prompt: `Are you sure you want to delete this library? This will delete all ${deleteAssetCount} contained assets from Immich and cannot be undone. Files will remain on disk.`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isConfirmedLibraryAssetCount) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
await handleDelete();
|
||||||
|
} else {
|
||||||
|
deletedLibrary = selectedLibrary;
|
||||||
|
await handleDelete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if confirmDeleteLibrary}
|
|
||||||
<ConfirmDialogue
|
|
||||||
id="warning-modal"
|
|
||||||
title="Warning!"
|
|
||||||
prompt="Are you sure you want to delete this library? This will delete all {deleteAssetCount} contained assets from Immich and cannot be undone. Files will remain on disk."
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => (confirmDeleteLibrary = null)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if toCreateLibrary}
|
{#if toCreateLibrary}
|
||||||
<LibraryUserPickerForm
|
<LibraryUserPickerForm
|
||||||
on:submit={({ detail }) => handleCreate(detail.ownerId)}
|
on:submit={({ detail }) => handleCreate(detail.ownerId)}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte';
|
||||||
import DeleteConfirmDialog from '$lib/components/admin-page/delete-confirm-dialogue.svelte';
|
import DeleteConfirmDialog from '$lib/components/admin-page/delete-confirm-dialogue.svelte';
|
||||||
import RestoreDialogue from '$lib/components/admin-page/restore-dialogue.svelte';
|
import RestoreDialogue from '$lib/components/admin-page/restore-dialogue.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
|
@ -9,7 +10,6 @@
|
||||||
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
||||||
import EditUserForm from '$lib/components/forms/edit-user-form.svelte';
|
import EditUserForm from '$lib/components/forms/edit-user-form.svelte';
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
NotificationType,
|
||||||
notificationController,
|
notificationController,
|
||||||
|
@ -153,12 +153,12 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if shouldShowPasswordResetSuccess}
|
{#if shouldShowPasswordResetSuccess}
|
||||||
<ConfirmDialogue
|
<ConfirmDialog
|
||||||
id="password-reset-success-modal"
|
id="password-reset-success-modal"
|
||||||
title="Password reset success"
|
title="Password reset success"
|
||||||
confirmText="Done"
|
confirmText="Done"
|
||||||
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
||||||
onClose={() => (shouldShowPasswordResetSuccess = false)}
|
onCancel={() => (shouldShowPasswordResetSuccess = false)}
|
||||||
hideCancelButton={true}
|
hideCancelButton={true}
|
||||||
confirmColor="green"
|
confirmColor="green"
|
||||||
>
|
>
|
||||||
|
@ -185,7 +185,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialog>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<table class="my-5 w-full text-left">
|
<table class="my-5 w-full text-left">
|
||||||
|
|
Loading…
Reference in a new issue