mirror of
https://github.com/immich-app/immich.git
synced 2026-02-04 08:49:01 +03:00
chore(web): bump immich/ui for tooltips (#24632)
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -717,8 +717,8 @@ importers:
|
||||
specifier: file:../open-api/typescript-sdk
|
||||
version: link:../open-api/typescript-sdk
|
||||
'@immich/ui':
|
||||
specifier: ^0.50.1
|
||||
version: 0.50.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)
|
||||
specifier: ^0.52.0
|
||||
version: 0.52.0(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)
|
||||
'@mapbox/mapbox-gl-rtl-text':
|
||||
specifier: 0.2.3
|
||||
version: 0.2.3(mapbox-gl@1.13.3)
|
||||
@@ -3054,8 +3054,8 @@ packages:
|
||||
peerDependencies:
|
||||
svelte: ^5.0.0
|
||||
|
||||
'@immich/ui@0.50.1':
|
||||
resolution: {integrity: sha512-fNlQGh75ZFa/UZAgJaYk9/ItHOXHNNzN4CunjCmE7WocVVkUZbUxopN9Ku3F5GULSqD/zJ5gNO6PQAZ1ZoSaaQ==}
|
||||
'@immich/ui@0.52.0':
|
||||
resolution: {integrity: sha512-ECQIE5qYNpe7Q5+hifIGUDaRQXBkPOp9dvZaHELWWzAGIhbwG+mUYwMpUgU2TO7fV5u8XU6nHyBuC055zApiWQ==}
|
||||
peerDependencies:
|
||||
svelte: ^5.0.0
|
||||
|
||||
@@ -10677,6 +10677,10 @@ packages:
|
||||
resolution: {integrity: sha512-i/w5Ie4tENfGYbdCo2iJ+oies0vOFd8QXWHopKOUzudfLCvnmeheF2PpHp89Z2azpc+c2su3lMiWO/SpP+429A==}
|
||||
engines: {node: '>=0.12.18'}
|
||||
|
||||
simple-icons@16.4.0:
|
||||
resolution: {integrity: sha512-8CKtCvx1Zq3L0CBsR4RR1MjGCXkXbzdspwl2yCxs8oWkstbzj2+DatRKDee/tuj3Ffd/2CDzwEky9RgG2yggew==}
|
||||
engines: {node: '>=0.12.18'}
|
||||
|
||||
sirv@2.0.4:
|
||||
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -15026,14 +15030,14 @@ snapshots:
|
||||
dependencies:
|
||||
svelte: 5.46.1
|
||||
|
||||
'@immich/ui@0.50.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)':
|
||||
'@immich/ui@0.52.0(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)':
|
||||
dependencies:
|
||||
'@immich/svelte-markdown-preprocess': 0.1.0(svelte@5.46.1)
|
||||
'@internationalized/date': 3.10.0
|
||||
'@mdi/js': 7.4.47
|
||||
bits-ui: 2.14.4(@internationalized/date@3.10.0)(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)))(svelte@5.46.1)
|
||||
luxon: 3.7.2
|
||||
simple-icons: 15.22.0
|
||||
simple-icons: 16.4.0
|
||||
svelte: 5.46.1
|
||||
svelte-highlight: 7.9.0
|
||||
tailwind-merge: 3.4.0
|
||||
@@ -24017,6 +24021,8 @@ snapshots:
|
||||
|
||||
simple-icons@15.22.0: {}
|
||||
|
||||
simple-icons@16.4.0: {}
|
||||
|
||||
sirv@2.0.4:
|
||||
dependencies:
|
||||
'@polka/url': 1.0.0-next.29
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"format": "prettier --check .",
|
||||
"format:fix": "prettier --write . && pnpm run format:i18n",
|
||||
"format:i18n": "pnpm dlx sort-json ../i18n/*.json",
|
||||
"test": "vitest --run",
|
||||
"test": "vitest",
|
||||
"test:cov": "vitest --coverage",
|
||||
"test:watch": "vitest dev",
|
||||
"prepare": "svelte-kit sync"
|
||||
@@ -28,7 +28,7 @@
|
||||
"@formatjs/icu-messageformat-parser": "^2.9.8",
|
||||
"@immich/justified-layout-wasm": "^0.4.3",
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@immich/ui": "^0.50.1",
|
||||
"@immich/ui": "^0.52.0",
|
||||
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@photo-sphere-viewer/core": "^5.14.0",
|
||||
|
||||
15
web/src/lib/components/TestWrapper.svelte
Normal file
15
web/src/lib/components/TestWrapper.svelte
Normal file
@@ -0,0 +1,15 @@
|
||||
<script lang="ts" generics="T extends Record<string, unknown>">
|
||||
import { TooltipProvider } from '@immich/ui';
|
||||
import type { Component } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
component: Component<T>;
|
||||
componentProps: T;
|
||||
};
|
||||
|
||||
const { component: Test, componentProps }: Props = $props();
|
||||
</script>
|
||||
|
||||
<TooltipProvider>
|
||||
<Test {...componentProps} />
|
||||
</TooltipProvider>
|
||||
@@ -1,4 +1,5 @@
|
||||
import { sdkMock } from '$lib/__mocks__/sdk.mock';
|
||||
import { renderWithTooltips } from '$tests/helpers';
|
||||
import { albumFactory } from '@test-data/factories/album-factory';
|
||||
import '@testing-library/jest-dom';
|
||||
import { render, waitFor, type RenderResult } from '@testing-library/svelte';
|
||||
@@ -88,7 +89,7 @@ describe('AlbumCard component', () => {
|
||||
const album = Object.freeze(albumFactory.build({ albumThumbnailAssetId: null }));
|
||||
|
||||
beforeEach(async () => {
|
||||
sut = render(AlbumCard, { album, onShowContextMenu });
|
||||
sut = renderWithTooltips(AlbumCard, { album, onShowContextMenu });
|
||||
|
||||
const albumImgElement = sut.getByTestId('album-image');
|
||||
await waitFor(() => expect(albumImgElement).toHaveAttribute('src'));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { renderWithTooltips } from '$tests/helpers';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { assetFactory } from '@test-data/factories/asset-factory';
|
||||
import '@testing-library/jest-dom';
|
||||
import { render } from '@testing-library/svelte';
|
||||
import DeleteAction from './delete-action.svelte';
|
||||
|
||||
let asset: AssetResponseDto;
|
||||
@@ -13,8 +13,12 @@ describe('DeleteAction component', () => {
|
||||
});
|
||||
|
||||
it('displays a button to move the asset to the trash bin', () => {
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn(), preAction: vi.fn() });
|
||||
expect(getByTitle('delete')).toBeInTheDocument();
|
||||
const { getByLabelText, queryByTitle } = renderWithTooltips(DeleteAction, {
|
||||
asset,
|
||||
onAction: vi.fn(),
|
||||
preAction: vi.fn(),
|
||||
});
|
||||
expect(getByLabelText('delete')).toBeInTheDocument();
|
||||
expect(queryByTitle('deletePermanently')).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -25,8 +29,12 @@ describe('DeleteAction component', () => {
|
||||
});
|
||||
|
||||
it('displays a button to permanently delete the asset', () => {
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn(), preAction: vi.fn() });
|
||||
expect(getByTitle('permanently_delete')).toBeInTheDocument();
|
||||
const { getByLabelText, queryByTitle } = renderWithTooltips(DeleteAction, {
|
||||
asset,
|
||||
onAction: vi.fn(),
|
||||
preAction: vi.fn(),
|
||||
});
|
||||
expect(getByLabelText('permanently_delete')).toBeInTheDocument();
|
||||
expect(queryByTitle('delete')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { preferences as preferencesStore, resetSavedUser, user as userStore } from '$lib/stores/user.store';
|
||||
import { renderWithTooltips } from '$tests/helpers';
|
||||
import { assetFactory } from '@test-data/factories/asset-factory';
|
||||
import { preferencesFactory } from '@test-data/factories/preferences-factory';
|
||||
import { userAdminFactory } from '@test-data/factories/user-factory';
|
||||
import '@testing-library/jest-dom';
|
||||
import { render } from '@testing-library/svelte';
|
||||
import AssetViewerNavBar from './asset-viewer-nav-bar.svelte';
|
||||
|
||||
describe('AssetViewerNavBar component', () => {
|
||||
@@ -16,12 +16,13 @@ describe('AssetViewerNavBar component', () => {
|
||||
showShareButton: false,
|
||||
preAction: () => {},
|
||||
onZoomImage: () => {},
|
||||
onCopyImage: () => {},
|
||||
onAction: () => {},
|
||||
onRunJob: () => {},
|
||||
onPlaySlideshow: () => {},
|
||||
onShowDetail: () => {},
|
||||
onClose: () => {},
|
||||
playOriginalVideo: false,
|
||||
setPlayOriginalVideo: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
@@ -51,8 +52,8 @@ describe('AssetViewerNavBar component', () => {
|
||||
preferencesStore.set(prefs);
|
||||
|
||||
const asset = assetFactory.build({ isTrashed: false });
|
||||
const { getByTitle } = render(AssetViewerNavBar, { asset, ...additionalProps });
|
||||
expect(getByTitle('go_back')).toBeInTheDocument();
|
||||
const { getByLabelText } = renderWithTooltips(AssetViewerNavBar, { asset, ...additionalProps });
|
||||
expect(getByLabelText('go_back')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('if the current user owns the asset', () => {
|
||||
@@ -65,8 +66,8 @@ describe('AssetViewerNavBar component', () => {
|
||||
const prefs = preferencesFactory.build({ cast: { gCastEnabled: false } });
|
||||
preferencesStore.set(prefs);
|
||||
|
||||
const { getByTitle } = render(AssetViewerNavBar, { asset, ...additionalProps });
|
||||
expect(getByTitle('delete')).toBeInTheDocument();
|
||||
const { getByLabelText } = renderWithTooltips(AssetViewerNavBar, { asset, ...additionalProps });
|
||||
expect(getByLabelText('delete')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock';
|
||||
import { sdkMock } from '$lib/__mocks__/sdk.mock';
|
||||
import ManagePeopleVisibility from '$lib/components/faces-page/manage-people-visibility.svelte';
|
||||
import type { PersonResponseDto } from '@immich/sdk';
|
||||
import { personFactory } from '@test-data/factories/person-factory';
|
||||
import { render } from '@testing-library/svelte';
|
||||
import { tick } from 'svelte';
|
||||
|
||||
describe('ManagePeopleVisibility Component', () => {
|
||||
let personVisible: PersonResponseDto;
|
||||
let personHidden: PersonResponseDto;
|
||||
let personWithoutName: PersonResponseDto;
|
||||
|
||||
beforeAll(() => {
|
||||
// Prevents errors from `img.decode()` in ImageThumbnail
|
||||
Object.defineProperty(HTMLImageElement.prototype, 'decode', {
|
||||
value: vi.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
||||
personVisible = personFactory.build({ isHidden: false });
|
||||
personHidden = personFactory.build({ isHidden: true });
|
||||
personWithoutName = personFactory.build({ isHidden: false, name: undefined });
|
||||
sdkMock.updatePeople.mockResolvedValue([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('does not update people when no changes are made', () => {
|
||||
const { getByText } = render(ManagePeopleVisibility, {
|
||||
props: {
|
||||
people: [personVisible, personHidden, personWithoutName],
|
||||
totalPeopleCount: 3,
|
||||
onClose: vi.fn(),
|
||||
loadNextPage: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
const saveButton = getByText('done');
|
||||
saveButton.click();
|
||||
expect(sdkMock.updatePeople).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// svelte animations require a real browser
|
||||
it.skip('hides unnamed people on first button press', () => {
|
||||
const { getByText, getByTitle } = render(ManagePeopleVisibility, {
|
||||
props: {
|
||||
people: [personVisible, personHidden, personWithoutName],
|
||||
totalPeopleCount: 3,
|
||||
onClose: vi.fn(),
|
||||
loadNextPage: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
getByTitle('hide_unnamed_people').click();
|
||||
getByText('done').click();
|
||||
|
||||
expect(sdkMock.updatePeople).toHaveBeenCalledWith({
|
||||
peopleUpdateDto: {
|
||||
people: [{ id: personWithoutName.id, isHidden: true }],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// svelte animations require a real browser
|
||||
it.skip('hides all people on second button press', async () => {
|
||||
const { getByText, getByTitle } = render(ManagePeopleVisibility, {
|
||||
props: {
|
||||
people: [personVisible, personHidden, personWithoutName],
|
||||
totalPeopleCount: 3,
|
||||
onClose: vi.fn(),
|
||||
loadNextPage: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
getByTitle('hide_unnamed_people').click();
|
||||
await tick();
|
||||
getByTitle('hide_all_people').click();
|
||||
getByText('done').click();
|
||||
|
||||
expect(sdkMock.updatePeople).toHaveBeenCalledWith({
|
||||
peopleUpdateDto: {
|
||||
people: expect.arrayContaining([
|
||||
{ id: personVisible.id, isHidden: true },
|
||||
{ id: personWithoutName.id, isHidden: true },
|
||||
]),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// svelte animations require a real browser
|
||||
it.skip('shows all people on third button press', async () => {
|
||||
const { getByText, getByTitle } = render(ManagePeopleVisibility, {
|
||||
props: {
|
||||
people: [personVisible, personHidden, personWithoutName],
|
||||
totalPeopleCount: 3,
|
||||
onClose: vi.fn(),
|
||||
loadNextPage: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
getByTitle('hide_unnamed_people').click();
|
||||
await tick();
|
||||
getByTitle('hide_all_people').click();
|
||||
await tick();
|
||||
getByTitle('show_all_people').click();
|
||||
getByText('done').click();
|
||||
|
||||
expect(sdkMock.updatePeople).toHaveBeenCalledWith({
|
||||
peopleUpdateDto: {
|
||||
people: [{ id: personHidden.id, isHidden: false }],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock';
|
||||
import { getVisualViewportMock } from '$lib/__mocks__/visual-viewport.mock';
|
||||
import Combobox from '$lib/components/shared-components/combobox.svelte';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
|
||||
describe('Combobox component', () => {
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
||||
vi.stubGlobal('visualViewport', getVisualViewportMock());
|
||||
});
|
||||
|
||||
it('shows selected option', () => {
|
||||
render(Combobox, {
|
||||
label: 'test',
|
||||
selectedOption: { label: 'option-1', value: 'option-1' },
|
||||
});
|
||||
|
||||
expect(screen.getByRole('combobox')).toHaveValue('option-1');
|
||||
});
|
||||
|
||||
it('clears the selected option when set to undefined', async () => {
|
||||
const { rerender } = render(Combobox, {
|
||||
label: 'test',
|
||||
selectedOption: { label: 'option-1', value: 'option-1' },
|
||||
});
|
||||
|
||||
await rerender({ selectedOption: undefined });
|
||||
expect(screen.getByRole('combobox')).toHaveValue('');
|
||||
});
|
||||
});
|
||||
@@ -21,7 +21,14 @@
|
||||
import { copyToClipboard, getReleaseType, semverToName } from '$lib/utils';
|
||||
import { maintenanceShouldRedirect } from '$lib/utils/maintenance';
|
||||
import { isAssetViewerRoute } from '$lib/utils/navigation';
|
||||
import { CommandPaletteContext, modalManager, setTranslations, toastManager, type ActionItem } from '@immich/ui';
|
||||
import {
|
||||
CommandPaletteDefaultProvider,
|
||||
TooltipProvider,
|
||||
modalManager,
|
||||
setTranslations,
|
||||
toastManager,
|
||||
type ActionItem,
|
||||
} from '@immich/ui';
|
||||
import { mdiAccountMultipleOutline, mdiBookshelf, mdiCog, mdiServer, mdiSync, mdiThemeLightDark } from '@mdi/js';
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -180,7 +187,7 @@
|
||||
</script>
|
||||
|
||||
<OnEvents {onReleaseEvent} />
|
||||
<CommandPaletteContext {commands} />
|
||||
<CommandPaletteDefaultProvider name="Global" actions={commands} />
|
||||
|
||||
<svelte:head>
|
||||
<title>{page.data.meta?.title || 'Web'} - Immich</title>
|
||||
@@ -228,15 +235,17 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if page.data.error}
|
||||
<ErrorLayout error={page.data.error}></ErrorLayout>
|
||||
{:else}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
<TooltipProvider>
|
||||
{#if page.data.error}
|
||||
<ErrorLayout error={page.data.error}></ErrorLayout>
|
||||
{:else}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
|
||||
{#if showNavigationLoadingBar}
|
||||
<NavigationLoadingBar />
|
||||
{/if}
|
||||
{#if showNavigationLoadingBar}
|
||||
<NavigationLoadingBar />
|
||||
{/if}
|
||||
|
||||
<DownloadPanel />
|
||||
<UploadPanel />
|
||||
<DownloadPanel />
|
||||
<UploadPanel />
|
||||
</TooltipProvider>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { getBytesWithUnit } from '$lib/utils/byte-units';
|
||||
import { getLibrary, getLibraryStatistics, type LibraryResponseDto } from '@immich/sdk';
|
||||
import { Button, CommandPaletteContext } from '@immich/ui';
|
||||
import { Button, CommandPaletteDefaultProvider } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { fade } from 'svelte/transition';
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<OnEvents {onLibraryCreate} {onLibraryUpdate} {onLibraryDelete} />
|
||||
|
||||
<CommandPaletteContext commands={[Create, ScanAll]} />
|
||||
<CommandPaletteDefaultProvider name={$t('library')} actions={[Create, ScanAll]} />
|
||||
|
||||
<AdminPageLayout breadcrumbs={[{ title: data.meta.title }]} actions={[ScanAll, Create]}>
|
||||
<section class="my-4">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
} from '$lib/services/library.service';
|
||||
import { getBytesWithUnit } from '$lib/utils/byte-units';
|
||||
import type { LibraryResponseDto } from '@immich/sdk';
|
||||
import { Code, CommandPaletteContext, Container, Heading, modalManager } from '@immich/ui';
|
||||
import { Code, CommandPaletteDefaultProvider, Container, Heading, modalManager } from '@immich/ui';
|
||||
import { mdiCameraIris, mdiChartPie, mdiFilterMinusOutline, mdiFolderOutline, mdiPlayCircle } from '@mdi/js';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<OnEvents {onLibraryUpdate} {onLibraryDelete} />
|
||||
|
||||
<CommandPaletteContext commands={[Edit, Delete, AddFolder, AddExclusionPattern, Scan]} />
|
||||
<CommandPaletteDefaultProvider name={$t('library')} actions={[Edit, Delete, AddFolder, AddExclusionPattern, Scan]} />
|
||||
|
||||
<AdminPageLayout
|
||||
breadcrumbs={[{ title: $t('external_libraries'), href: AppRoute.ADMIN_LIBRARIES }, { title: library.name }]}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { queueManager } from '$lib/managers/queue-manager.svelte';
|
||||
import { getQueuesActions } from '$lib/services/queue.service';
|
||||
import { type QueueResponseDto } from '@immich/sdk';
|
||||
import { CommandPaletteContext, Container, type ActionItem } from '@immich/ui';
|
||||
import { CommandPaletteDefaultProvider, Container, type ActionItem } from '@immich/ui';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { PageData } from './$types';
|
||||
@@ -33,7 +33,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<CommandPaletteContext {commands} />
|
||||
<CommandPaletteDefaultProvider name={$t('admin.queues')} actions={commands} />
|
||||
|
||||
<OnEvents {onQueueUpdate} />
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
|
||||
import { getSystemConfigActions } from '$lib/services/system-config.service';
|
||||
import { Alert, CommandPaletteContext, Container } from '@immich/ui';
|
||||
import { Alert, CommandPaletteDefaultProvider, Container } from '@immich/ui';
|
||||
import {
|
||||
mdiAccountOutline,
|
||||
mdiBackupRestore,
|
||||
@@ -214,7 +214,7 @@
|
||||
);
|
||||
</script>
|
||||
|
||||
<CommandPaletteContext commands={[CopyToClipboard, Upload, Download]} />
|
||||
<CommandPaletteDefaultProvider name={$t('admin.system_settings')} actions={[CopyToClipboard, Upload, Download]} />
|
||||
|
||||
<AdminPageLayout breadcrumbs={[{ title: data.meta.title }]} actions={[CopyToClipboard, Download, Upload]}>
|
||||
<Container size="large" center>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { getByteUnitString } from '$lib/utils/byte-units';
|
||||
import { searchUsersAdmin, type UserAdminResponseDto } from '@immich/sdk';
|
||||
import { Button, CommandPaletteContext, Container, Icon } from '@immich/ui';
|
||||
import { Button, CommandPaletteDefaultProvider, Container, Icon } from '@immich/ui';
|
||||
import { mdiInfinity } from '@mdi/js';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -44,7 +44,7 @@
|
||||
{onUserAdminDeleted}
|
||||
/>
|
||||
|
||||
<CommandPaletteContext commands={[Create]} />
|
||||
<CommandPaletteDefaultProvider name={$t('users')} actions={[Create]} />
|
||||
|
||||
<AdminPageLayout breadcrumbs={[{ title: data.meta.title }]} actions={[Create]}>
|
||||
<Container center size="large">
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
Alert,
|
||||
Badge,
|
||||
Code,
|
||||
CommandPaletteContext,
|
||||
CommandPaletteDefaultProvider,
|
||||
Container,
|
||||
getByteUnitString,
|
||||
Heading,
|
||||
@@ -99,7 +99,7 @@
|
||||
{onUserAdminDeleted}
|
||||
/>
|
||||
|
||||
<CommandPaletteContext commands={[ResetPassword, ResetPinCode, Update, Delete, Restore]} />
|
||||
<CommandPaletteDefaultProvider name={$t('user')} actions={[ResetPassword, ResetPinCode, Update, Delete, Restore]} />
|
||||
|
||||
<AdminPageLayout
|
||||
breadcrumbs={[{ title: $t('admin.user_management'), href: AppRoute.ADMIN_USERS }, { title: user.name }]}
|
||||
|
||||
@@ -25,6 +25,8 @@ const config = {
|
||||
alias: {
|
||||
$lib: 'src/lib',
|
||||
'$lib/*': 'src/lib/*',
|
||||
$tests: 'src/../tests',
|
||||
'$tests/*': 'src/../tests/*',
|
||||
'@test-data': 'src/test-data',
|
||||
$i18n: '../i18n',
|
||||
'chromecast-caf-sender': './node_modules/@types/chromecast-caf-sender/index.d.ts',
|
||||
|
||||
13
web/tests/helpers.ts
Normal file
13
web/tests/helpers.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import TestWrapper from '$lib/components/TestWrapper.svelte';
|
||||
import { render, type RenderResult } from '@testing-library/svelte';
|
||||
import { type Component } from 'svelte';
|
||||
|
||||
export const renderWithTooltips = <T extends Record<string, unknown>, K extends Component<T>>(
|
||||
component: K,
|
||||
props: T,
|
||||
) => {
|
||||
return render(TestWrapper as Component<{ component: K; componentProps: T }>, {
|
||||
component,
|
||||
componentProps: props,
|
||||
}) as unknown as RenderResult<K>;
|
||||
};
|
||||
Reference in New Issue
Block a user