diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 1483b4312b..51e023056d 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -34,7 +34,7 @@ jobs: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 diff --git a/.github/workflows/close-duplicates.yml b/.github/workflows/close-duplicates.yml index 8470e0e18c..ba360b50dc 100644 --- a/.github/workflows/close-duplicates.yml +++ b/.github/workflows/close-duplicates.yml @@ -35,7 +35,7 @@ jobs: needs: [get_body, should_run] if: ${{ needs.should_run.outputs.should_run == 'true' }} container: - image: ghcr.io/immich-app/mdq:main@sha256:d8ae47cf2e6cf4e2559bd57a60b73674fe44f897cba2c2bddff2987a05be10a4 + image: ghcr.io/immich-app/mdq:main@sha256:6b8450bfc06770af1af66bce9bf2ced7d1d9b90df1a59fc4c83a17777a9f6723 outputs: checked: ${{ steps.get_checkbox.outputs.checked }} steps: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2946f33783..c0cb9e1da1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/init@755f44910c12a3d7ca0d8c6e42c048b3362f7cec # v3.30.8 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -63,7 +63,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/autobuild@755f44910c12a3d7ca0d8c6e42c048b3362f7cec # v3.30.8 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -76,6 +76,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/analyze@755f44910c12a3d7ca0d8c6e42c048b3362f7cec # v3.30.8 with: category: '/language:${{matrix.language}}' diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index 1a29bebe47..537282b789 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -52,7 +52,7 @@ jobs: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 diff --git a/.github/workflows/fix-format.yml b/.github/workflows/fix-format.yml index 1c57828b0c..dd61764bbc 100644 --- a/.github/workflows/fix-format.yml +++ b/.github/workflows/fix-format.yml @@ -29,7 +29,7 @@ jobs: persist-credentials: true - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index a6fa5c802f..5a369ad13b 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -65,7 +65,7 @@ jobs: uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 @@ -128,7 +128,7 @@ jobs: name: release-apk-signed - name: Create draft release - uses: softprops/action-gh-release@aec2ec56f94eb8180ceec724245f64ef008b89f5 # v2.4.0 + uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1 with: draft: true tag_name: ${{ env.IMMICH_VERSION }} diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index a0d89be598..6d768efaaf 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -21,7 +21,7 @@ jobs: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 # Setup .npmrc file to publish to npm - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ed57a59ba..d95ede71e4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,7 +60,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -97,7 +97,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -137,7 +137,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -172,7 +172,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -209,7 +209,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -240,7 +240,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -281,7 +281,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -320,7 +320,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -352,7 +352,7 @@ jobs: persist-credentials: false submodules: 'recursive' - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -400,7 +400,7 @@ jobs: persist-credentials: false submodules: 'recursive' - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -507,7 +507,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -544,7 +544,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -599,7 +599,7 @@ jobs: with: persist-credentials: false - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md index f9c00c7df7..fbb4cd8c23 100644 --- a/docs/docs/administration/backup-and-restore.md +++ b/docs/docs/administration/backup-and-restore.md @@ -57,6 +57,7 @@ Then please follow the steps in the following section for restoring the database ```bash title='Backup' +# Replace with the database username - usually postgres unless you have changed it. docker exec -t immich_postgres pg_dumpall --clean --if-exists --username= | gzip > "/path/to/backup/dump.sql.gz" ``` @@ -69,16 +70,18 @@ docker compose create # Create Docker containers for Immich apps witho docker start immich_postgres # Start Postgres server sleep 10 # Wait for Postgres server to start up # Check the database user if you deviated from the default +# Replace with the database username - usually postgres unless you have changed it. gunzip --stdout "/path/to/backup/dump.sql.gz" \ | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \ | docker exec -i immich_postgres psql --dbname=postgres --username= # Restore Backup docker compose up -d # Start remainder of Immich apps ``` - + ```powershell title='Backup' +# Replace with the database username - usually postgres unless you have changed it. [System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=)) ``` @@ -92,13 +95,15 @@ docker compose create # Create Docker containers for docker start immich_postgres # Start Postgres server sleep 10 # Wait for Postgres server to start up docker exec -it immich_postgres bash # Enter the Docker shell and run the following command -# Check the database user if you deviated from the default. If your backup ends in `.gz`, replace `cat` with `gunzip --stdout` +# If your backup ends in `.gz`, replace `cat` with `gunzip --stdout` +# Replace with the database username - usually postgres unless you have changed it. + cat "/dump.sql" | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" | psql --dbname=postgres --username= exit # Exit the Docker shell docker compose up -d # Start remainder of Immich apps ``` - + Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.), in which case you need to delete the `DB_DATA_LOCATION` folder to reset the database. diff --git a/docs/docs/administration/reverse-proxy.md b/docs/docs/administration/reverse-proxy.md index f13814d91f..5c9e47b010 100644 --- a/docs/docs/administration/reverse-proxy.md +++ b/docs/docs/administration/reverse-proxy.md @@ -6,6 +6,10 @@ Users can deploy a custom reverse proxy that forwards requests to Immich. This w Immich does not support being served on a sub-path such as `location /immich {`. It has to be served on the root path of a (sub)domain. ::: +:::info +If your reverse proxy uses the [Let's Encrypt](https://letsencrypt.org/) [http-01 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge), you may want to verify that the Immich well-known endpoint (`/.well-known/immich`) gets correctly routed to Immich, otherwise it will likely be routed elsewhere and the mobile app may run into connection issues. +::: + ### Nginx example config Below is an example config for nginx. Make sure to set `public_url` to the front-facing URL of your instance, and `backend_url` to the path of the Immich server. @@ -37,29 +41,14 @@ server { location / { proxy_pass http://:2283; } + + # useful when using Let's Encrypt http-01 challenge + # location = /.well-known/immich { + # proxy_pass http://:2283; + # } } ``` -#### Compatibility with Let's Encrypt - -In the event that your nginx configuration includes a section for Let's Encrypt, it's likely that you have a segment similar to the following: - -```nginx -location ~ /.well-known { - ... -} -``` - -This particular `location` directive can inadvertently prevent mobile clients from reaching the `/.well-known/immich` path, which is crucial for discovery. Usual error message for this case is: "Your app major version is not compatible with the server". To remedy this, you should introduce an additional location block specifically for this path, ensuring that requests are correctly proxied to the Immich server: - -```nginx -location = /.well-known/immich { - proxy_pass http://:2283; -} -``` - -By doing so, you'll maintain the functionality of Let's Encrypt while allowing mobile clients to access the necessary Immich path without obstruction. - ### Caddy example config As an alternative to nginx, you can also use [Caddy](https://caddyserver.com/) as a reverse proxy (with automatic HTTPS configuration). Below is an example config. diff --git a/docs/docs/community-guides.mdx b/docs/docs/community-guides.mdx deleted file mode 100644 index 505ec93e77..0000000000 --- a/docs/docs/community-guides.mdx +++ /dev/null @@ -1,12 +0,0 @@ -# Community Guides - -This page lists community guides that are written around Immich, but not officially supported by the development team. - -:::warning -This list comes with no guarantees about security, performance, reliability, or accuracy. Use at your own risk. -::: - -import CommunityGuides from '../src/components/community-guides.tsx'; -import React from 'react'; - - diff --git a/docs/docs/community-projects.mdx b/docs/docs/community-projects.mdx deleted file mode 100644 index eb41090cd6..0000000000 --- a/docs/docs/community-projects.mdx +++ /dev/null @@ -1,12 +0,0 @@ -# Community Projects - -This page lists community projects that are built around Immich, but not officially supported by the development team. - -:::warning -This list comes with no guarantees about security, performance, reliability, or accuracy. Use at your own risk. -::: - -import CommunityProjects from '../src/components/community-projects.tsx'; -import React from 'react'; - - diff --git a/docs/docs/features/command-line-interface.md b/docs/docs/features/command-line-interface.md index 436b499e50..2b35d62ce8 100644 --- a/docs/docs/features/command-line-interface.md +++ b/docs/docs/features/command-line-interface.md @@ -182,7 +182,7 @@ For example to get a list of files that would be uploaded for further processing: ```bash -immich upload --dry-run . | tail -n +4 | jq .newFiles[] +immich upload --dry-run . | tail -n +6 | jq .newFiles[] ``` ### Obtain the API Key diff --git a/docs/docs/features/ml-hardware-acceleration.md b/docs/docs/features/ml-hardware-acceleration.md index 7f92c25449..685f23932c 100644 --- a/docs/docs/features/ml-hardware-acceleration.md +++ b/docs/docs/features/ml-hardware-acceleration.md @@ -57,6 +57,22 @@ You do not need to redo any machine learning jobs after enabling hardware accele - Ensure the server's kernel version is new enough to use the device for hardware acceleration. - Expect higher RAM usage when using OpenVINO compared to CPU processing. +#### OpenVINO-WSL + +- Ensure your container can access the /dev/dri directory, you can verify this by doing `docker exec -t immich_machine_learning ls -la /dev/dri`. If this is not the case execute `getent group render` and `getent group video` on the WSL host, then add those groups to hwaccel.ml.yaml + ```yaml + openvino-wsl: + devices: + - /dev/dri:/dev/dri + - /dev/dxg:/dev/dxg + volumes: + - /dev/bus/usb:/dev/bus/usb + - /usr/lib/wsl:/usr/lib/wsl + group_add: + - 44 # Replace this number with the number you found with getent group video + - 992 # Replace this number with the number you found with getent group render + ``` + #### RKNN - You must have a supported Rockchip SoC: only RK3566, RK3568, RK3576 and RK3588 are supported at this moment. diff --git a/docs/docs/features/mobile-app.mdx b/docs/docs/features/mobile-app.mdx index 82a2976b41..2d34507a26 100644 --- a/docs/docs/features/mobile-app.mdx +++ b/docs/docs/features/mobile-app.mdx @@ -3,7 +3,6 @@ import { mdiCloudOffOutline, mdiCloudCheckOutline } from '@mdi/js'; import MobileAppDownload from '/docs/partials/_mobile-app-download.md'; import MobileAppLogin from '/docs/partials/_mobile-app-login.md'; import MobileAppBackup from '/docs/partials/_mobile-app-backup.md'; -import { cloudDonePath, cloudOffPath } from '@site/src/components/svg-paths'; # Mobile App diff --git a/docs/docs/partials/_mobile-app-download.md b/docs/docs/partials/_mobile-app-download.md index 72a3053440..31cf62bf81 100644 --- a/docs/docs/partials/_mobile-app-download.md +++ b/docs/docs/partials/_mobile-app-download.md @@ -1,5 +1,6 @@ The mobile app can be downloaded from the following places: +- Obtainium: You can get your Obtainium config link from the [Utilities page of your Immich server](https://my.immich.app/utilities). - [Google Play Store](https://play.google.com/store/apps/details?id=app.alextran.immich) - [Apple App Store](https://apps.apple.com/us/app/immich/id1613945652) - [F-Droid](https://f-droid.org/packages/app.alextran.immich) diff --git a/docs/src/components/community-guides.tsx b/docs/src/components/community-guides.tsx deleted file mode 100644 index 08c8e096d9..0000000000 --- a/docs/src/components/community-guides.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import Link from '@docusaurus/Link'; -import React from 'react'; - -interface CommunityGuidesProps { - title: string; - description: string; - url: string; -} - -const guides: CommunityGuidesProps[] = [ - { - title: 'Cloudflare Tunnels with SSO/OAuth', - description: `Setting up Cloudflare Tunnels and a SaaS App for Immich.`, - url: 'https://github.com/immich-app/immich/discussions/8299', - }, - { - title: 'Database backup in TrueNAS', - description: `Create a database backup with pgAdmin in TrueNAS.`, - url: 'https://github.com/immich-app/immich/discussions/8809', - }, - { - title: 'Unraid backup scripts', - description: `Back up your assets in Unraid with a pre-prepared script.`, - url: 'https://github.com/immich-app/immich/discussions/8416', - }, - { - title: 'Sync folders with albums', - description: `synchronize folders in imported library with albums having the folders name.`, - url: 'https://github.com/immich-app/immich/discussions/3382', - }, - { - title: 'Immich Podman Quadlets Handbook', - description: - 'A rewrite of the original Immich Docker Compose file using Podman Quadlets, with a set of extra guides in the repository’s wiki.', - url: 'https://github.com/linux-universe/immich-podman-quadlets/blob/main/README.md', - }, - { - title: 'Podman/Quadlets Install', - description: 'Documentation for simple podman setup using quadlets.', - url: 'https://github.com/tbelway/immich-podman-quadlets/blob/main/docs/install/podman-quadlet.md', - }, - { - title: 'Google Photos import + albums', - description: 'Import your Google Photos files into Immich and add your albums.', - url: 'https://github.com/immich-app/immich/discussions/1340', - }, - { - title: 'Access Immich with custom domain', - description: 'Access your local Immich installation over the internet using your own domain.', - url: 'https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md', - }, - { - title: 'Nginx caching map server', - description: 'Increase privacy by using nginx as a caching proxy in front of a map tile server.', - url: 'https://github.com/pcouy/pcouy.github.io/blob/main/_posts/2024-08-30-proxying-a-map-tile-server-for-increased-privacy.md', - }, - { - title: 'fail2ban setup instructions', - description: 'How to configure an existing fail2ban installation to block incorrect login attempts.', - url: 'https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948', - }, - { - title: 'Immich remote access with NordVPN Meshnet', - description: 'Access Immich with an end-to-end encrypted connection.', - url: 'https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access', - }, - { - title: 'Trust Self Signed Certificates with Immich - OAuth Setup', - description: - 'Set up Certificate Authority trust with Immich, and your private OAuth2/OpenID service, while using a private CA for HTTPS commication.', - url: 'https://github.com/immich-app/immich/discussions/18614', - }, -]; - -function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element { - return ( -
-
-

- {title} -

- -

{description}

-

- {url} -

-
-
- - View Guide - -
-
- ); -} - -export default function CommunityGuides(): JSX.Element { - return ( -
- {guides.map((guides) => ( - - ))} -
- ); -} diff --git a/docs/src/components/community-projects.tsx b/docs/src/components/community-projects.tsx deleted file mode 100644 index 6b74ae7ad8..0000000000 --- a/docs/src/components/community-projects.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import Link from '@docusaurus/Link'; -import React from 'react'; - -interface CommunityProjectProps { - title: string; - description: string; - url: string; -} - -const projects: CommunityProjectProps[] = [ - { - title: 'immich-go', - description: `An alternative to the immich-CLI that doesn't depend on nodejs. It specializes in importing Google Photos Takeout archives.`, - url: 'https://github.com/simulot/immich-go', - }, - { - title: 'ImmichFrame', - description: 'Run an Immich slideshow in a photo frame.', - url: 'https://github.com/3rob3/ImmichFrame', - }, - { - title: 'API Album Sync', - description: 'A Python script to sync folders as albums.', - url: 'https://git.orenit.solutions/open/immichalbumpull', - }, - { - title: 'Immich-Tools', - description: 'Provides scripts for handling problems on the repair page.', - url: 'https://github.com/clumsyCoder00/Immich-Tools', - }, - { - title: 'Lightroom Publisher: mi.Immich.Publisher', - description: 'Lightroom plugin to publish photos from Lightroom collections to Immich albums.', - url: 'https://github.com/midzelis/mi.Immich.Publisher', - }, - { - title: 'Lightroom Immich Plugin: lrc-immich-plugin', - description: - 'Lightroom plugin to publish, export photos from Lightroom to Immich. Import from Immich to Lightroom is also supported.', - url: 'https://blog.fokuspunk.de/lrc-immich-plugin/', - }, - { - title: 'Immich-Tiktok-Remover', - description: 'Script to search for and remove TikTok videos from your Immich library.', - url: 'https://github.com/mxc2/immich-tiktok-remover', - }, - { - title: 'Immich Android TV', - description: 'Unofficial Immich Android TV app.', - url: 'https://github.com/giejay/Immich-Android-TV', - }, - { - title: 'Create albums from folders', - description: 'A Python script to create albums based on the folder structure of an external library.', - url: 'https://github.com/Salvoxia/immich-folder-album-creator', - }, - { - title: 'Powershell Module PSImmich', - description: 'Powershell Module for the Immich API', - url: 'https://github.com/hanpq/PSImmich', - }, - { - title: 'Immich Distribution', - description: 'Snap package for easy install and zero-care auto updates of Immich. Self-hosted photo management.', - url: 'https://immich-distribution.nsg.cc', - }, - { - title: 'Immich Kiosk', - description: 'Lightweight slideshow to run on kiosk devices and browsers.', - url: 'https://github.com/damongolding/immich-kiosk', - }, - { - title: 'Immich Power Tools', - description: 'Power tools for organizing your immich library.', - url: 'https://github.com/varun-raj/immich-power-tools', - }, - { - title: 'Immich Public Proxy', - description: - 'Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.', - url: 'https://github.com/alangrainger/immich-public-proxy', - }, - { - title: 'Immich Kodi', - description: 'Unofficial Kodi plugin for Immich.', - url: 'https://github.com/vladd11/immich-kodi', - }, - { - title: 'Immich Downloader', - description: 'Downloads a configurable number of random photos based on people or album ID.', - url: 'https://github.com/jon6fingrs/immich-dl', - }, - { - title: 'Immich Upload Optimizer', - description: 'Automatically optimize files uploaded to Immich in order to save storage space', - url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer', - }, - { - title: 'Immich Machine Learning Load Balancer', - description: 'Speed up your machine learning by load balancing your requests to multiple computers', - url: 'https://github.com/apetersson/immich_ml_balancer', - }, - { - title: 'Immich Drop Uploader', - description: 'A tiny, zero-login web app for collecting photos/videos from anyone into your Immich server.', - url: 'https://github.com/Nasogaa/immich-drop', - }, - { - title: 'Immich Birthday Sync', - description: 'Bulk-upload and -download birthdays, with CardDAV sync support', - url: 'https://github.com/sid3windr/immich-birthday', - }, - { - title: 'Immich Stack', - description: 'Auto-stack photos with identical filenames and differing extensions (i.e. JPG+RAW)', - url: 'https://github.com/sid3windr/immich-stack', - }, - { - title: 'Immich Stack', - description: 'Automatically groups similar photos into stacks within the Immich photo management system.', - url: 'https://github.com/Majorfi/immich-stack/', - }, -]; - -function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element { - return ( -
-
-

- {title} -

- -

{description}

-

- {url} -

-
-
- - View Link - -
-
- ); -} - -export default function CommunityProjects(): JSX.Element { - return ( -
- {projects.map((project) => ( - - ))} -
- ); -} diff --git a/docs/src/components/svg-paths.ts b/docs/src/components/svg-paths.ts deleted file mode 100644 index 0903392307..0000000000 --- a/docs/src/components/svg-paths.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const discordPath = - 'M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z'; -export const discordViewBox = '0 0 126.644 96'; diff --git a/docs/static/_redirects b/docs/static/_redirects index ecbdf19303..ce4b670246 100644 --- a/docs/static/_redirects +++ b/docs/static/_redirects @@ -27,8 +27,10 @@ /administration/password-login /administration/system-settings 307 /features/search /features/searching 307 /features/smart-search /features/searching 307 -/guides/api-album-sync /community-projects 307 -/guides/remove-offline-files /community-projects 307 +/guides/api-album-sync https://awesome.immich.app/ 307 +/guides/remove-offline-files https://awesome.immich.app/ 307 +/community-guides https://awesome.immich.app/ 307 +/community-projects https://awesome.immich.app/ 307 /overview/introduction /overview/quick-start 307 /overview/welcome /overview/quick-start 307 /docs/* /:splat 307 diff --git a/e2e/src/web/specs/auth.e2e-spec.ts b/e2e/src/web/specs/auth.e2e-spec.ts index 173131ec5e..a14a177917 100644 --- a/e2e/src/web/specs/auth.e2e-spec.ts +++ b/e2e/src/web/specs/auth.e2e-spec.ts @@ -38,6 +38,7 @@ test.describe('Registration', () => { await page.getByRole('button', { name: 'User Privacy' }).click(); await page.getByRole('button', { name: 'Storage Template' }).click(); await page.getByRole('button', { name: 'Backups' }).click(); + await page.getByRole('button', { name: 'Mobile App' }).click(); await page.getByRole('button', { name: 'Done' }).click(); // success @@ -85,6 +86,7 @@ test.describe('Registration', () => { await page.getByRole('button', { name: 'Theme' }).click(); await page.getByRole('button', { name: 'Language' }).click(); await page.getByRole('button', { name: 'User Privacy' }).click(); + await page.getByRole('button', { name: 'Mobile App' }).click(); await page.getByRole('button', { name: 'Done' }).click(); // success diff --git a/i18n/en.json b/i18n/en.json index e1702611a7..d265c9b9d8 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -211,6 +211,8 @@ "notification_email_ignore_certificate_errors_description": "Ignore TLS certificate validation errors (not recommended)", "notification_email_password_description": "Password to use when authenticating with the email server", "notification_email_port_description": "Port of the email server (e.g 25, 465, or 587)", + "notification_email_secure": "SMTPS", + "notification_email_secure_description": "Use SMTPS (SMTP over TLS)", "notification_email_sent_test_email_button": "Send test email and save", "notification_email_setting_description": "Settings for sending email notifications", "notification_email_test_email": "Send test email", @@ -466,9 +468,11 @@ "api_key_description": "This value will only be shown once. Please be sure to copy it before closing the window.", "api_key_empty": "Your API Key name shouldn't be empty", "api_keys": "API Keys", + "app_architecture_variant": "Variant (Architecture)", "app_bar_signout_dialog_content": "Are you sure you want to sign out?", "app_bar_signout_dialog_ok": "Yes", "app_bar_signout_dialog_title": "Sign out", + "app_download_links": "App Download Links", "app_settings": "App Settings", "appears_in": "Appears in", "apply_count": "Apply ({count, number})", @@ -1346,6 +1350,8 @@ "minute": "Minute", "minutes": "Minutes", "missing": "Missing", + "mobile_app": "Mobile App", + "mobile_app_download_onboarding_note": "You can access these options again from the Utilities page.", "model": "Model", "month": "Month", "monthly_title_text_date_format": "MMMM y", @@ -1426,6 +1432,8 @@ "notifications": "Notifications", "notifications_setting_description": "Manage notifications", "oauth": "OAuth", + "obtainium_configurator": "Obtainium Configurator", + "obtainium_configurator_instructions": "Please create an API key and select a variant to create your Obtainium configuration link.", "official_immich_resources": "Official Immich Resources", "offline": "Offline", "offset": "Offset", diff --git a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart index bdaaa426c5..46307046b4 100644 --- a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart +++ b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart @@ -17,6 +17,7 @@ class SystemConfigSmtpTransportDto { required this.ignoreCert, required this.password, required this.port, + required this.secure, required this.username, }); @@ -30,6 +31,8 @@ class SystemConfigSmtpTransportDto { /// Maximum value: 65535 num port; + bool secure; + String username; @override @@ -38,6 +41,7 @@ class SystemConfigSmtpTransportDto { other.ignoreCert == ignoreCert && other.password == password && other.port == port && + other.secure == secure && other.username == username; @override @@ -47,10 +51,11 @@ class SystemConfigSmtpTransportDto { (ignoreCert.hashCode) + (password.hashCode) + (port.hashCode) + + (secure.hashCode) + (username.hashCode); @override - String toString() => 'SystemConfigSmtpTransportDto[host=$host, ignoreCert=$ignoreCert, password=$password, port=$port, username=$username]'; + String toString() => 'SystemConfigSmtpTransportDto[host=$host, ignoreCert=$ignoreCert, password=$password, port=$port, secure=$secure, username=$username]'; Map toJson() { final json = {}; @@ -58,6 +63,7 @@ class SystemConfigSmtpTransportDto { json[r'ignoreCert'] = this.ignoreCert; json[r'password'] = this.password; json[r'port'] = this.port; + json[r'secure'] = this.secure; json[r'username'] = this.username; return json; } @@ -75,6 +81,7 @@ class SystemConfigSmtpTransportDto { ignoreCert: mapValueOfType(json, r'ignoreCert')!, password: mapValueOfType(json, r'password')!, port: num.parse('${json[r'port']}'), + secure: mapValueOfType(json, r'secure')!, username: mapValueOfType(json, r'username')!, ); } @@ -127,6 +134,7 @@ class SystemConfigSmtpTransportDto { 'ignoreCert', 'password', 'port', + 'secure', 'username', }; } diff --git a/open-api/bin/generate-open-api.sh b/open-api/bin/generate-open-api.sh index 1ce33b96e6..43292089d7 100755 --- a/open-api/bin/generate-open-api.sh +++ b/open-api/bin/generate-open-api.sh @@ -15,7 +15,7 @@ function dart { patch --no-backup-if-mismatch -u api.mustache =0.4.7'} hasBin: true - happy-dom@20.0.0: - resolution: {integrity: sha512-GkWnwIFxVGCf2raNrxImLo397RdGhLapj5cT3R2PT7FwL62Ze1DROhzmYW7+J3p9105DYMVenEejEbnq5wA37w==} + happy-dom@20.0.2: + resolution: {integrity: sha512-pYOyu624+6HDbY+qkjILpQGnpvZOusItCk+rvF5/V+6NkcgTKnbOldpIy22tBnxoaLtlM9nXgoqAcW29/B7CIw==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -15689,29 +15689,29 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))': dependencies: - '@sveltejs/kit': 2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@sveltejs/kit': 2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) - '@sveltejs/enhanced-img@0.8.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(rollup@4.52.4)(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@sveltejs/enhanced-img@0.8.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(rollup@4.52.4)(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) magic-string: 0.30.19 sharp: 0.34.4 svelte: 5.39.11 svelte-parse-markup: 0.1.5(svelte@5.39.11) - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) vite-imagetools: 8.0.0(rollup@4.52.4) zimmerframe: 1.1.4 transitivePeerDependencies: - rollup - supports-color - '@sveltejs/kit@2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@sveltejs/kit@2.46.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.6(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 @@ -15724,28 +15724,28 @@ snapshots: set-cookie-parser: 2.7.1 sirv: 3.0.2 svelte: 5.39.11 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) optionalDependencies: '@opentelemetry/api': 1.9.0 - '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.39.11 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)))(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 magic-string: 0.30.19 svelte: 5.39.11 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - vitefu: 1.1.1(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) transitivePeerDependencies: - supports-color @@ -15967,12 +15967,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14 '@tailwindcss/oxide-win32-x64-msvc': 4.1.14 - '@tailwindcss/vite@4.1.14(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@tailwindcss/vite@4.1.14(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@tailwindcss/node': 4.1.14 '@tailwindcss/oxide': 4.1.14 tailwindcss: 4.1.14 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) '@testing-library/dom@10.4.0': dependencies: @@ -15994,13 +15994,13 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/svelte@5.2.8(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.1)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@testing-library/svelte@5.2.8(svelte@5.39.11)(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@testing-library/dom': 10.4.0 svelte: 5.39.11 optionalDependencies: - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.1)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)': dependencies: @@ -16309,7 +16309,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@20.19.2': + '@types/node@20.19.21': dependencies: undici-types: 6.21.0 @@ -16317,7 +16317,7 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@24.7.1': + '@types/node@24.7.2': dependencies: undici-types: 7.14.0 optional: true @@ -16567,7 +16567,7 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -16582,11 +16582,11 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.1)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -16601,7 +16601,7 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.1)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -16621,13 +16621,13 @@ snapshots: optionalDependencies: vite: 7.1.9(@types/node@22.18.10)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - '@vitest/mocker@3.2.4(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.19 optionalDependencies: - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -19136,9 +19136,9 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 - happy-dom@20.0.0: + happy-dom@20.0.2: dependencies: - '@types/node': 20.19.2 + '@types/node': 20.19.21 '@types/whatwg-mimetype': 3.0.2 whatwg-mimetype: 3.0.0 @@ -24013,13 +24013,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): + vite-node@3.2.4(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -24061,7 +24061,7 @@ snapshots: terser: 5.43.1 yaml: 2.8.1 - vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): + vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) @@ -24070,22 +24070,22 @@ snapshots: rollup: 4.52.4 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.7.1 + '@types/node': 24.7.2 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.1 terser: 5.43.1 yaml: 2.8.1 - vitefu@1.1.1(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)): + vitefu@1.1.1(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)): optionalDependencies: - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - vitest-fetch-mock@0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)): + vitest-fetch-mock@0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)): dependencies: - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 @@ -24113,7 +24113,7 @@ snapshots: optionalDependencies: '@types/debug': 4.1.12 '@types/node': 22.18.10 - happy-dom: 20.0.0 + happy-dom: 20.0.2 jsdom: 26.1.0(canvas@2.11.2(encoding@0.1.13)) transitivePeerDependencies: - jiti @@ -24129,7 +24129,7 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.10)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 @@ -24157,7 +24157,7 @@ snapshots: optionalDependencies: '@types/debug': 4.1.12 '@types/node': 22.18.10 - happy-dom: 20.0.0 + happy-dom: 20.0.2 jsdom: 26.1.0(canvas@2.11.2) transitivePeerDependencies: - jiti @@ -24173,11 +24173,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.1)(happy-dom@20.0.0)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(happy-dom@20.0.2)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -24195,13 +24195,13 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.9(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 - '@types/node': 24.7.1 - happy-dom: 20.0.0 + '@types/node': 24.7.2 + happy-dom: 20.0.2 jsdom: 26.1.0(canvas@2.11.2) transitivePeerDependencies: - jiti diff --git a/server/src/config.ts b/server/src/config.ts index 66c03450fa..1a88b0a2d3 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -159,6 +159,7 @@ export interface SystemConfig { ignoreCert: boolean; host: string; port: number; + secure: boolean; username: string; password: string; }; @@ -356,6 +357,7 @@ export const defaults = Object.freeze({ ignoreCert: false, host: '', port: 587, + secure: false, username: '', password: '', }, diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index 1facc6c331..f12846fc9a 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -463,6 +463,9 @@ class SystemConfigSmtpTransportDto { @Max(65_535) port!: number; + @ValidateBoolean() + secure!: boolean; + @IsString() username!: string; diff --git a/server/src/repositories/email.repository.ts b/server/src/repositories/email.repository.ts index 78c89b4a9d..1bc4f0981a 100644 --- a/server/src/repositories/email.repository.ts +++ b/server/src/repositories/email.repository.ts @@ -23,6 +23,7 @@ export type SendEmailOptions = { export type SmtpOptions = { host: string; port?: number; + secure?: boolean; username?: string; password?: string; ignoreCert?: boolean; diff --git a/server/src/schema/migrations/1744910873969-InitialMigration.ts b/server/src/schema/migrations/1744910873969-InitialMigration.ts index 53a55d860e..b703a47536 100644 --- a/server/src/schema/migrations/1744910873969-InitialMigration.ts +++ b/server/src/schema/migrations/1744910873969-InitialMigration.ts @@ -16,7 +16,9 @@ export async function up(db: Kysely): Promise { rows: [lastMigration], } = await lastMigrationSql.execute(db); if (lastMigration?.name !== 'AddMissingIndex1744910873956') { - throw new Error('Invalid upgrade path. For more information, see https://immich.app/errors#typeorm-upgrade'); + throw new Error( + 'Invalid upgrade path. For more information, see https://docs.immich.app/errors/#typeorm-upgrade', + ); } logger.log('Database has up to date TypeORM migrations, skipping initial Kysely migration'); return; diff --git a/server/src/services/notification-admin.service.spec.ts b/server/src/services/notification-admin.service.spec.ts index 4a747d41a3..c200897719 100644 --- a/server/src/services/notification-admin.service.spec.ts +++ b/server/src/services/notification-admin.service.spec.ts @@ -14,6 +14,7 @@ const smtpTransport = Object.freeze({ ignoreCert: false, host: 'localhost', port: 587, + secure: false, username: 'test', password: 'test', }, diff --git a/server/src/services/notification.service.spec.ts b/server/src/services/notification.service.spec.ts index a96caf5ac2..403ed44631 100644 --- a/server/src/services/notification.service.spec.ts +++ b/server/src/services/notification.service.spec.ts @@ -40,6 +40,7 @@ const configs = { ignoreCert: false, host: 'localhost', port: 587, + secure: false, username: 'test', password: 'test', }, diff --git a/server/src/services/storage.service.ts b/server/src/services/storage.service.ts index 50dffd5465..71cf0d0ce8 100644 --- a/server/src/services/storage.service.ts +++ b/server/src/services/storage.service.ts @@ -115,7 +115,7 @@ export class StorageService extends BaseService { if (!path.startsWith(previous)) { throw new Error( - 'Detected an inconsistent media location. For more information, see https://immich.app/errors#inconsistent-media-location', + 'Detected an inconsistent media location. For more information, see https://docs.immich.app/errors#inconsistent-media-location', ); } diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index 5a9c7f4df3..c2dff1aaed 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -197,6 +197,7 @@ const updatedConfig = Object.freeze({ transport: { host: '', port: 587, + secure: false, username: '', password: '', ignoreCert: false, diff --git a/web/package.json b/web/package.json index 45cbdcc451..5eacb72b85 100644 --- a/web/package.json +++ b/web/package.json @@ -18,7 +18,7 @@ "lint:fix": "npm run lint -- --fix", "format": "prettier --check .", "format:fix": "prettier --write . && npm run format:i18n", - "format:i18n": "pnpx sort-json ../i18n/*.json", + "format:i18n": "pnpm dlx sort-json ../i18n/*.json", "test": "vitest --run", "test:cov": "vitest --coverage", "test:watch": "vitest dev", diff --git a/web/src/lib/components/admin-settings/NotificationSettings.svelte b/web/src/lib/components/admin-settings/NotificationSettings.svelte index d1d698d4fa..65ca6f9bd7 100644 --- a/web/src/lib/components/admin-settings/NotificationSettings.svelte +++ b/web/src/lib/components/admin-settings/NotificationSettings.svelte @@ -45,6 +45,7 @@ transport: { host: config.notifications.smtp.transport.host, port: config.notifications.smtp.transport.port, + secure: config.notifications.smtp.transport.secure, username: config.notifications.smtp.transport.username, password: config.notifications.smtp.transport.password, ignoreCert: config.notifications.smtp.transport.ignoreCert, @@ -128,6 +129,13 @@ savedConfig.notifications.smtp.transport.password} /> + + + import AppDownloadModal from '$lib/modals/AppDownloadModal.svelte'; + import ObtainiumConfigModal from '$lib/modals/ObtainiumConfigModal.svelte'; + import { Button, HStack, modalManager } from '@immich/ui'; + import { mdiCellphoneArrowDownVariant, mdiLinkEdit } from '@mdi/js'; + import { t } from 'svelte-i18n'; + + + + + + +

{$t('mobile_app_download_onboarding_note')}

diff --git a/web/src/lib/components/shared-components/context-menu/context-menu.svelte b/web/src/lib/components/shared-components/context-menu/context-menu.svelte index aad037148c..c98a986973 100644 --- a/web/src/lib/components/shared-components/context-menu/context-menu.svelte +++ b/web/src/lib/components/shared-components/context-menu/context-menu.svelte @@ -61,7 +61,7 @@
diff --git a/web/src/lib/components/utilities-page/utilities-menu.svelte b/web/src/lib/components/utilities-page/utilities-menu.svelte index fc747dc6af..bf7090e310 100644 --- a/web/src/lib/components/utilities-page/utilities-menu.svelte +++ b/web/src/lib/components/utilities-page/utilities-menu.svelte @@ -1,7 +1,15 @@ + + + +
+
+ + + Get it on F-Droid + +
+ +
+ + + Get it on Google Play + +
+ +
+ + + Download on the App Store + +
+
+
+
diff --git a/web/src/lib/modals/ObtainiumConfigModal.svelte b/web/src/lib/modals/ObtainiumConfigModal.svelte new file mode 100644 index 0000000000..d7132f2f85 --- /dev/null +++ b/web/src/lib/modals/ObtainiumConfigModal.svelte @@ -0,0 +1,94 @@ + + + + +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ {#if inputUrl && inputApiKey && archVariant} + + Get it on Obtainium + + {:else} + + {/if} +
+
+
+
diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index c35fb6a893..9604ecbbc9 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -60,14 +60,14 @@ interface UploadRequestOptions { } export class AbortError extends Error { - name = 'AbortError'; + override name = 'AbortError'; } class ApiError extends Error { - name = 'ApiError'; + override name = 'ApiError'; constructor( - public message: string, + public override message: string, public statusCode: number, public details: string, ) { diff --git a/web/src/routes/auth/onboarding/+page.svelte b/web/src/routes/auth/onboarding/+page.svelte index 44f3792a5b..c046c5fadf 100644 --- a/web/src/routes/auth/onboarding/+page.svelte +++ b/web/src/routes/auth/onboarding/+page.svelte @@ -5,6 +5,7 @@ import OnboardingCard from '$lib/components/onboarding-page/onboarding-card.svelte'; import OnboardingHello from '$lib/components/onboarding-page/onboarding-hello.svelte'; import OnboardingLocale from '$lib/components/onboarding-page/onboarding-language.svelte'; + import OnboardingMobileApp from '$lib/components/onboarding-page/onboarding-mobile-app.svelte'; import OnboardingServerPrivacy from '$lib/components/onboarding-page/onboarding-server-privacy.svelte'; import OnboardingStorageTemplate from '$lib/components/onboarding-page/onboarding-storage-template.svelte'; import OnboardingTheme from '$lib/components/onboarding-page/onboarding-theme.svelte'; @@ -14,7 +15,14 @@ import { retrieveServerConfig, retrieveSystemConfig, serverConfig } from '$lib/stores/server-config.store'; import { user } from '$lib/stores/user.store'; import { setUserOnboarding, updateAdminOnboarding } from '@immich/sdk'; - import { mdiCloudCheckOutline, mdiHarddisk, mdiIncognito, mdiThemeLightDark, mdiTranslate } from '@mdi/js'; + import { + mdiCellphoneArrowDownVariant, + mdiCloudCheckOutline, + mdiHarddisk, + mdiIncognito, + mdiThemeLightDark, + mdiTranslate, + } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; @@ -26,6 +34,7 @@ | typeof OnboardingStorageTemplate | typeof OnboardingServerPrivacy | typeof OnboardingUserPrivacy + | typeof OnboardingMobileApp | typeof OnboardingLocale; role: OnboardingRole; title?: string; @@ -76,6 +85,13 @@ title: $t('admin.backup_onboarding_title'), icon: mdiCloudCheckOutline, }, + { + name: 'mobile_app', + component: OnboardingMobileApp, + role: OnboardingRole.USER, + title: $t('mobile_app'), + icon: mdiCellphoneArrowDownVariant, // or you can use mdiCellphone + }, ]); let index = $state(0); diff --git a/web/tsconfig.json b/web/tsconfig.json index c7bc16f52b..afebee51ad 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -6,6 +6,7 @@ "forceConsistentCasingInFileNames": true, "module": "es2022", "moduleResolution": "bundler", + "noImplicitOverride": true, "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true,