mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix: enter now submits the date modals (#25053)
* fix: enter now submits the date modals * use FormModal * apply prettier * fix unit test
This commit is contained in:
parent
c411151560
commit
4cb56edebf
4 changed files with 111 additions and 114 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
import { getPreferredTimeZone, getTimezones, toIsoDate } from '$lib/modals/timezone-utils';
|
import { getPreferredTimeZone, getTimezones, toIsoDate } from '$lib/modals/timezone-utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updateAsset } from '@immich/sdk';
|
import { updateAsset } from '@immich/sdk';
|
||||||
import { Button, HStack, Label, Modal, ModalBody, ModalFooter } from '@immich/ui';
|
import { FormModal, Label } from '@immich/ui';
|
||||||
import { mdiCalendarEdit } from '@mdi/js';
|
import { mdiCalendarEdit } from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
||||||
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
||||||
|
|
||||||
const handleClose = async () => {
|
const onSubmit = async () => {
|
||||||
if (!date.isValid || !selectedOption) {
|
if (!date.isValid || !selectedOption) {
|
||||||
onClose(false);
|
onClose(false);
|
||||||
return;
|
return;
|
||||||
|
|
@ -49,25 +49,25 @@
|
||||||
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal title={$t('edit_date_and_time')} icon={mdiCalendarEdit} onClose={() => onClose(false)} size="small">
|
<FormModal
|
||||||
<ModalBody>
|
title={$t('edit_date_and_time')}
|
||||||
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
icon={mdiCalendarEdit}
|
||||||
<DateInput
|
onClose={() => onClose(false)}
|
||||||
class="immich-form-input text-gray-700 w-full mb-2"
|
{onSubmit}
|
||||||
id="datetime"
|
submitText={$t('confirm')}
|
||||||
type="datetime-local"
|
disabled={!date.isValid || !selectedOption}
|
||||||
bind:value={selectedDate}
|
size="small"
|
||||||
/>
|
>
|
||||||
{#if timezoneInput}
|
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
||||||
<div class="w-full">
|
<DateInput
|
||||||
<Combobox bind:selectedOption label={$t('timezone')} options={timezones} placeholder={$t('search_timezone')} />
|
class="immich-form-input text-gray-700 w-full mb-2"
|
||||||
</div>
|
id="datetime"
|
||||||
{/if}
|
type="datetime-local"
|
||||||
</ModalBody>
|
bind:value={selectedDate}
|
||||||
<ModalFooter>
|
/>
|
||||||
<HStack fullWidth>
|
{#if timezoneInput}
|
||||||
<Button shape="round" color="secondary" fullWidth onclick={() => onClose(false)}>{$t('cancel')}</Button>
|
<div class="w-full">
|
||||||
<Button shape="round" type="submit" fullWidth onclick={handleClose}>{$t('confirm')}</Button>
|
<Combobox bind:selectedOption label={$t('timezone')} options={timezones} placeholder={$t('search_timezone')} />
|
||||||
</HStack>
|
</div>
|
||||||
</ModalFooter>
|
{/if}
|
||||||
</Modal>
|
</FormModal>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ describe('DateSelectionModal component', () => {
|
||||||
const getRelativeInputToggle = () => screen.getByTestId('edit-by-offset-switch');
|
const getRelativeInputToggle = () => screen.getByTestId('edit-by-offset-switch');
|
||||||
const getDateInput = () => screen.getByLabelText('date_and_time') as HTMLInputElement;
|
const getDateInput = () => screen.getByLabelText('date_and_time') as HTMLInputElement;
|
||||||
const getTimeZoneInput = () => screen.getByLabelText('timezone') as HTMLInputElement;
|
const getTimeZoneInput = () => screen.getByLabelText('timezone') as HTMLInputElement;
|
||||||
const getCancelButton = () => screen.getByText('cancel');
|
const getCancelButton = () => screen.getByRole('button', { name: /cancel/i });
|
||||||
const getConfirmButton = () => screen.getByText('confirm');
|
const getConfirmButton = () => screen.getByRole('button', { name: /confirm/i });
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import { getOwnedAssetsWithWarning } from '$lib/utils/asset-utils';
|
import { getOwnedAssetsWithWarning } from '$lib/utils/asset-utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updateAssets } from '@immich/sdk';
|
import { updateAssets } from '@immich/sdk';
|
||||||
import { Button, Field, HStack, Label, Modal, ModalBody, ModalFooter, Switch } from '@immich/ui';
|
import { Field, FormModal, Label, Switch } from '@immich/ui';
|
||||||
import { mdiCalendarEdit } from '@mdi/js';
|
import { mdiCalendarEdit } from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
||||||
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
const onSubmit = async () => {
|
||||||
const ids = getOwnedAssetsWithWarning(assets, $user);
|
const ids = getOwnedAssetsWithWarning(assets, $user);
|
||||||
try {
|
try {
|
||||||
if (showRelative && (selectedDuration || selectedOption)) {
|
if (showRelative && (selectedDuration || selectedOption)) {
|
||||||
|
|
@ -63,66 +63,62 @@
|
||||||
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal title={$t('edit_date_and_time')} icon={mdiCalendarEdit} onClose={() => onClose(false)} size="small">
|
<FormModal
|
||||||
<ModalBody>
|
title={$t('edit_date_and_time')}
|
||||||
<Field label={$t('edit_date_and_time_by_offset')}>
|
icon={mdiCalendarEdit}
|
||||||
<Switch data-testid="edit-by-offset-switch" bind:checked={showRelative} class="mb-2" />
|
onClose={() => onClose(false)}
|
||||||
</Field>
|
{onSubmit}
|
||||||
{#if showRelative}
|
submitText={$t('confirm')}
|
||||||
<Label for="relativedatetime" class="block mb-1">{$t('offset')}</Label>
|
disabled={!date.isValid}
|
||||||
<DurationInput
|
size="small"
|
||||||
class="immich-form-input w-full text-gray-700 mb-2"
|
>
|
||||||
id="relativedatetime"
|
<Field label={$t('edit_date_and_time_by_offset')}>
|
||||||
bind:value={selectedDuration}
|
<Switch data-testid="edit-by-offset-switch" bind:checked={showRelative} class="mb-2" />
|
||||||
/>
|
</Field>
|
||||||
{:else}
|
{#if showRelative}
|
||||||
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
<Label for="relativedatetime" class="block mb-1">{$t('offset')}</Label>
|
||||||
<DateInput class="immich-form-input w-full mb-2" id="datetime" type="datetime-local" bind:value={selectedDate} />
|
<DurationInput
|
||||||
{/if}
|
class="immich-form-input w-full text-gray-700 mb-2"
|
||||||
<div class="w-full">
|
id="relativedatetime"
|
||||||
<Combobox
|
bind:value={selectedDuration}
|
||||||
bind:selectedOption
|
/>
|
||||||
label={$t('timezone')}
|
{:else}
|
||||||
options={timezones}
|
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
||||||
placeholder={$t('search_timezone')}
|
<DateInput class="immich-form-input w-full mb-2" id="datetime" type="datetime-local" bind:value={selectedDate} />
|
||||||
onSelect={(option) => (lastSelectedTimezone = option as ZoneOption)}
|
{/if}
|
||||||
></Combobox>
|
<div class="w-full">
|
||||||
</div>
|
<Combobox
|
||||||
<!-- <Card color="secondary" class={!showRelative || !currentInterval ? 'invisible' : ''}>
|
bind:selectedOption
|
||||||
<CardBody class="p-2">
|
label={$t('timezone')}
|
||||||
<div class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-3 items-center">
|
options={timezones}
|
||||||
<div class="col-span-2 immich-form-label" data-testid="interval-preview">Preview</div>
|
placeholder={$t('search_timezone')}
|
||||||
<Text size="small" class="-mt-2 immich-form-label col-span-2"
|
onSelect={(option) => (lastSelectedTimezone = option as ZoneOption)}
|
||||||
>Showing changes for first selected asset only</Text
|
></Combobox>
|
||||||
>
|
</div>
|
||||||
<label class="immich-form-label" for="from">Before</label>
|
<!-- <Card color="secondary" class={!showRelative || !currentInterval ? 'invisible' : ''}>
|
||||||
<DateInput
|
<CardBody class="p-2">
|
||||||
class="dark:text-gray-300 text-gray-700 text-base"
|
<div class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-3 items-center">
|
||||||
id="from"
|
<div class="col-span-2 immich-form-label" data-testid="interval-preview">Preview</div>
|
||||||
type="datetime-local"
|
<Text size="small" class="-mt-2 immich-form-label col-span-2"
|
||||||
readonly
|
>Showing changes for first selected asset only</Text
|
||||||
bind:value={before}
|
>
|
||||||
/>
|
<label class="immich-form-label" for="from">Before</label>
|
||||||
<label class="immich-form-label" for="to">After</label>
|
<DateInput
|
||||||
<DateInput
|
class="dark:text-gray-300 text-gray-700 text-base"
|
||||||
class="dark:text-gray-300 text-gray-700 text-base"
|
id="from"
|
||||||
id="to"
|
type="datetime-local"
|
||||||
type="datetime-local"
|
readonly
|
||||||
readonly
|
bind:value={before}
|
||||||
bind:value={after}
|
/>
|
||||||
/>
|
<label class="immich-form-label" for="to">After</label>
|
||||||
</div>
|
<DateInput
|
||||||
</CardBody>
|
class="dark:text-gray-300 text-gray-700 text-base"
|
||||||
</Card> -->
|
id="to"
|
||||||
</ModalBody>
|
type="datetime-local"
|
||||||
<ModalFooter>
|
readonly
|
||||||
<HStack fullWidth>
|
bind:value={after}
|
||||||
<Button shape="round" color="secondary" fullWidth onclick={() => onClose(false)}>
|
/>
|
||||||
{$t('cancel')}
|
</div>
|
||||||
</Button>
|
</CardBody>
|
||||||
<Button shape="round" color="primary" fullWidth onclick={handleConfirm} disabled={!date.isValid}>
|
</Card> -->
|
||||||
{$t('confirm')}
|
</FormModal>
|
||||||
</Button>
|
|
||||||
</HStack>
|
|
||||||
</ModalFooter>
|
|
||||||
</Modal>
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import { getPreferredTimeZone, getTimezones, toDatetime, type ZoneOption } from '$lib/modals/timezone-utils';
|
import { getPreferredTimeZone, getTimezones, toDatetime, type ZoneOption } from '$lib/modals/timezone-utils';
|
||||||
import { Button, HStack, Modal, ModalBody, ModalFooter, VStack } from '@immich/ui';
|
import { FormModal, HStack, VStack } from '@immich/ui';
|
||||||
import { mdiNavigationVariantOutline } from '@mdi/js';
|
import { mdiNavigationVariantOutline } from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
timelineManager: TimelineManager;
|
timelineManager: TimelineManager;
|
||||||
onClose: (asset?: TimelineAsset) => void;
|
onClose: (asset?: TimelineAsset) => void;
|
||||||
|
|
@ -20,7 +21,7 @@
|
||||||
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
||||||
let selectedOption: ZoneOption | undefined = $derived(getPreferredTimeZone(initialDate, undefined, timezones));
|
let selectedOption: ZoneOption | undefined = $derived(getPreferredTimeZone(initialDate, undefined, timezones));
|
||||||
|
|
||||||
const handleClose = async () => {
|
const onSubmit = async () => {
|
||||||
if (!date.isValid || !selectedOption) {
|
if (!date.isValid || !selectedOption) {
|
||||||
onClose();
|
onClose();
|
||||||
return;
|
return;
|
||||||
|
|
@ -36,26 +37,26 @@
|
||||||
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal title={$t('navigate_to_time')} icon={mdiNavigationVariantOutline} onClose={() => onClose()}>
|
<FormModal
|
||||||
<ModalBody>
|
title={$t('navigate_to_time')}
|
||||||
<VStack fullWidth>
|
icon={mdiNavigationVariantOutline}
|
||||||
<HStack fullWidth>
|
onClose={() => onClose()}
|
||||||
<label class="immich-form-label" for="datetime">{$t('date_and_time')}</label>
|
{onSubmit}
|
||||||
</HStack>
|
submitText={$t('confirm')}
|
||||||
<HStack fullWidth>
|
disabled={!date.isValid || !selectedOption}
|
||||||
<DateInput
|
size="medium"
|
||||||
class="immich-form-input text-gray-700 w-full"
|
>
|
||||||
id="datetime"
|
<VStack fullWidth>
|
||||||
type="datetime-local"
|
|
||||||
bind:value={selectedDate}
|
|
||||||
/>
|
|
||||||
</HStack>
|
|
||||||
</VStack>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter>
|
|
||||||
<HStack fullWidth>
|
<HStack fullWidth>
|
||||||
<Button shape="round" color="secondary" fullWidth onclick={() => onClose()}>{$t('cancel')}</Button>
|
<label class="immich-form-label" for="datetime">{$t('date_and_time')}</label>
|
||||||
<Button shape="round" type="submit" fullWidth onclick={handleClose}>{$t('confirm')}</Button>
|
|
||||||
</HStack>
|
</HStack>
|
||||||
</ModalFooter>
|
<HStack fullWidth>
|
||||||
</Modal>
|
<DateInput
|
||||||
|
class="immich-form-input text-gray-700 w-full"
|
||||||
|
id="datetime"
|
||||||
|
type="datetime-local"
|
||||||
|
bind:value={selectedDate}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
|
</FormModal>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue