diff --git a/docker/.env.example b/docker/.env.example index e24a0208bb..18c96c3534 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -56,21 +56,6 @@ ENABLE_MAPBOX=false MAPBOX_KEY= - - -################################################################################### -# WEB - Required -################################################################################### - -# This is the URL of your vm/server where you host Immich, so that the web frontend -# know where can it make the request to. -# For example: If your server IP address is 10.1.11.50, the environment variable will -# be VITE_SERVER_ENDPOINT=http://10.1.11.50:2283/api -# !CAUTION! THERE IS NO FORWARD SLASH AT THE END - -VITE_SERVER_ENDPOINT= - - #################################################################################### # WEB - Optional #################################################################################### diff --git a/server/apps/immich/src/config/app.config.ts b/server/apps/immich/src/config/app.config.ts index b2509db908..304bee8643 100644 --- a/server/apps/immich/src/config/app.config.ts +++ b/server/apps/immich/src/config/app.config.ts @@ -16,6 +16,5 @@ export const immichAppConfig: ConfigModuleOptions = { then: Joi.string().optional().allow(null, ''), otherwise: Joi.string().required(), }), - VITE_SERVER_ENDPOINT: Joi.string().required(), }), }; diff --git a/server/entrypoint.sh b/server/entrypoint.sh deleted file mode 100644 index 9f35169bf6..0000000000 --- a/server/entrypoint.sh +++ /dev/null @@ -1 +0,0 @@ -npm start immich \ No newline at end of file diff --git a/web/src/api/api.ts b/web/src/api/api.ts index 12b7dee9a8..d8454350ec 100644 --- a/web/src/api/api.ts +++ b/web/src/api/api.ts @@ -16,7 +16,7 @@ class ImmichApi { public authenticationApi: AuthenticationApi; public deviceInfoApi: DeviceInfoApi; public serverInfoApi: ServerInfoApi; - private config = new Configuration({ basePath: serverEndpoint }); + private config = new Configuration({ basePath: '/api' }); constructor() { this.userApi = new UserApi(this.config); @@ -34,6 +34,12 @@ class ImmichApi { public removeAccessToken() { this.config.accessToken = undefined; } + + public setBaseUrl(baseUrl: string) { + this.config.basePath = baseUrl; + } } export const api = new ImmichApi(); +export const serverApi = new ImmichApi(); +serverApi.setBaseUrl('http://immich-server:3001'); diff --git a/web/src/hooks.ts b/web/src/hooks.ts index 44f9a33e0d..788f169eb0 100644 --- a/web/src/hooks.ts +++ b/web/src/hooks.ts @@ -1,6 +1,6 @@ import type { ExternalFetch, GetSession, Handle } from '@sveltejs/kit'; import * as cookie from 'cookie'; -import { api } from '@api'; +import { api, serverApi } from '@api'; export const handle: Handle = async ({ event, resolve }) => { const cookies = cookie.parse(event.request.headers.get('cookie') || ''); @@ -11,8 +11,8 @@ export const handle: Handle = async ({ event, resolve }) => { const accessToken = cookies['immich_access_token']; try { - api.setAccessToken(accessToken); - const { data } = await api.userApi.getMyUserInfo(); + serverApi.setAccessToken(accessToken); + const { data } = await serverApi.userApi.getMyUserInfo(); event.locals.user = data; return await resolve(event); diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index b9098f8a84..9d18e1ff0b 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -60,7 +60,7 @@ }); $: { - if (album.assets.length < 6) { + if (album.assets?.length < 6) { thumbnailSize = Math.floor(viewWidth / album.assets.length - album.assets.length); } else { thumbnailSize = Math.floor(viewWidth / 6 - 6); diff --git a/web/src/lib/components/shared-components/status-box.svelte b/web/src/lib/components/shared-components/status-box.svelte index 1fecc700b4..fe92641a9a 100644 --- a/web/src/lib/components/shared-components/status-box.svelte +++ b/web/src/lib/components/shared-components/status-box.svelte @@ -82,11 +82,6 @@ <div class="text-xs"> <p class="text-sm font-medium text-immich-primary">Server</p> - <input - class="border p-2 rounded-md bg-gray-200 mt-2 text-immich-primary font-medium" - value={endpoint} - disabled={true} - /> <div class="flex justify-items-center justify-between mt-2"> <p>Status</p> diff --git a/web/src/lib/stores/assets.ts b/web/src/lib/stores/assets.ts index 35865b022f..107a98763f 100644 --- a/web/src/lib/stores/assets.ts +++ b/web/src/lib/stores/assets.ts @@ -29,3 +29,7 @@ export const getAssetsInfo = async () => { console.log('Error [getAssetsInfo]'); } }; + +export const setAssetInfo = (data: AssetResponseDto[]) => { + assets.set(data); +}; diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index edcdcdaa7d..8c1aa6be55 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -168,7 +168,7 @@ async function fileUploader(asset: File, uploadType: UploadType) { uploadAssetsStore.updateProgress(deviceAssetId, percentComplete); }; - request.open('POST', `${serverEndpoint}/asset/upload`); + request.open('POST', `api/asset/upload`); request.send(formData); } catch (e) { diff --git a/web/src/routes/admin/index.svelte b/web/src/routes/admin/index.svelte index 8da545eba1..641821802d 100644 --- a/web/src/routes/admin/index.svelte +++ b/web/src/routes/admin/index.svelte @@ -2,10 +2,12 @@ import type { Load } from '@sveltejs/kit'; import { api, UserResponseDto } from '@api'; - export const load: Load = async () => { + export const load: Load = async ({ fetch }) => { try { - const { data: allUsers } = await api.userApi.getAllUsers(false); - const { data: user } = await api.userApi.getMyUserInfo(); + const [user, allUsers] = await Promise.all([ + fetch('/data/user/get-my-user-info').then((r) => r.json()), + fetch('/data/user/get-all-users?isAll=false').then((r) => r.json()) + ]); return { status: 200, diff --git a/web/src/routes/albums/[albumId]/index.svelte b/web/src/routes/albums/[albumId]/index.svelte index 73d7b2d20f..7f1a2fd506 100644 --- a/web/src/routes/albums/[albumId]/index.svelte +++ b/web/src/routes/albums/[albumId]/index.svelte @@ -2,13 +2,15 @@ export const prerender = false; import type { Load } from '@sveltejs/kit'; - import { AlbumResponseDto, api } from '@api'; + import { AlbumResponseDto } from '@api'; - export const load: Load = async ({ params }) => { + export const load: Load = async ({ fetch, params }) => { try { const albumId = params['albumId']; - const { data: albumInfo } = await api.albumApi.getAlbumInfo(albumId); + const albumInfo = await fetch(`/data/album/get-album-info?albumId=${albumId}`).then((r) => + r.json() + ); return { status: 200, diff --git a/web/src/routes/albums/[albumId]/photos/[assetId].svelte b/web/src/routes/albums/[albumId]/photos/[assetId].svelte index 5a5db2e620..e646a19f55 100644 --- a/web/src/routes/albums/[albumId]/photos/[assetId].svelte +++ b/web/src/routes/albums/[albumId]/photos/[assetId].svelte @@ -1,12 +1,10 @@ <script context="module" lang="ts"> export const prerender = false; - - import { api } from '@api'; import type { Load } from '@sveltejs/kit'; export const load: Load = async ({ params }) => { try { - await api.userApi.getMyUserInfo(); + await fetch('/data/user/get-my-user-info'); } catch (e) { return { status: 302, diff --git a/web/src/routes/albums/index.svelte b/web/src/routes/albums/index.svelte index 0921a786f0..fcd4df23f0 100644 --- a/web/src/routes/albums/index.svelte +++ b/web/src/routes/albums/index.svelte @@ -9,10 +9,12 @@ import SideBar from '$lib/components/shared-components/side-bar/side-bar.svelte'; import { AlbumResponseDto, api } from '@api'; - export const load: Load = async () => { + export const load: Load = async ({ fetch }) => { try { - const { data: user } = await api.userApi.getMyUserInfo(); - const { data: albums } = await api.albumApi.getAllAlbums(); + const [user, albums] = await Promise.all([ + fetch('/data/user/get-my-user-info').then((r) => r.json()), + fetch('/data/album/get-all-albums').then((r) => r.json()) + ]); return { status: 200, diff --git a/web/src/routes/data/README.md b/web/src/routes/data/README.md new file mode 100644 index 0000000000..9067c01fb2 --- /dev/null +++ b/web/src/routes/data/README.md @@ -0,0 +1 @@ +This directory contain SSR endpoints to user serverApi instance to make request directly to DNS \ No newline at end of file diff --git a/web/src/routes/data/album/get-album-info.ts b/web/src/routes/data/album/get-album-info.ts new file mode 100644 index 0000000000..ddb637eec2 --- /dev/null +++ b/web/src/routes/data/album/get-album-info.ts @@ -0,0 +1,18 @@ +import { AlbumResponseDto, serverApi } from '@api'; +import type { RequestEvent, RequestHandlerOutput } from '@sveltejs/kit'; + +export const GET = async ({ + url +}: RequestEvent): Promise<RequestHandlerOutput<AlbumResponseDto>> => { + try { + const albumId = url.searchParams.get('albumId') || ''; + const { data } = await serverApi.albumApi.getAlbumInfo(albumId); + return { + body: data + }; + } catch { + return { + status: 500 + }; + } +}; diff --git a/web/src/routes/data/album/get-all-albums.ts b/web/src/routes/data/album/get-all-albums.ts new file mode 100644 index 0000000000..3f0fb69b54 --- /dev/null +++ b/web/src/routes/data/album/get-all-albums.ts @@ -0,0 +1,18 @@ +import { AlbumResponseDto, serverApi } from '@api'; +import type { RequestEvent, RequestHandler, RequestHandlerOutput } from '@sveltejs/kit'; + +export const GET = async ({ + url +}: RequestEvent): Promise<RequestHandlerOutput<AlbumResponseDto[]>> => { + try { + const isShared = url.searchParams.get('isShared') === 'true' || undefined; + const { data } = await serverApi.albumApi.getAllAlbums(isShared); + return { + body: data + }; + } catch { + return { + status: 500 + }; + } +}; diff --git a/web/src/routes/data/asset/get-all-assets.ts b/web/src/routes/data/asset/get-all-assets.ts new file mode 100644 index 0000000000..d175061f97 --- /dev/null +++ b/web/src/routes/data/asset/get-all-assets.ts @@ -0,0 +1,15 @@ +import { AssetResponseDto, serverApi } from '@api'; +import type { RequestHandlerOutput } from '@sveltejs/kit'; + +export const GET = async (): Promise<RequestHandlerOutput<AssetResponseDto[]>> => { + try { + const { data } = await serverApi.assetApi.getAllAssets(); + return { + body: data + }; + } catch { + return { + status: 500 + }; + } +}; diff --git a/web/src/routes/data/user/get-all-users.ts b/web/src/routes/data/user/get-all-users.ts new file mode 100644 index 0000000000..00a7ecb3ff --- /dev/null +++ b/web/src/routes/data/user/get-all-users.ts @@ -0,0 +1,17 @@ +import { serverApi, UserResponseDto } from '@api'; +import type { RequestEvent, RequestHandlerOutput } from '@sveltejs/kit'; + +export const GET = async ({url} : RequestEvent): Promise<RequestHandlerOutput<UserResponseDto[]>> => { + try { + const isAll = url.searchParams.get('isAll') === 'true'; + + const { data } = await serverApi.userApi.getAllUsers(isAll); + return { + body: data + }; + } catch { + return { + status: 500 + }; + } +}; diff --git a/web/src/routes/data/user/get-my-user-info.ts b/web/src/routes/data/user/get-my-user-info.ts new file mode 100644 index 0000000000..65cc8c5baa --- /dev/null +++ b/web/src/routes/data/user/get-my-user-info.ts @@ -0,0 +1,15 @@ +import { serverApi, UserResponseDto } from '@api'; +import type { RequestHandlerOutput } from '@sveltejs/kit'; + +export const GET = async (): Promise<RequestHandlerOutput<UserResponseDto>> => { + try { + const { data } = await serverApi.userApi.getMyUserInfo(); + return { + body: data + }; + } catch { + return { + status: 500 + }; + } +}; diff --git a/web/src/routes/index.svelte b/web/src/routes/index.svelte index 6ade4a468e..188547b830 100644 --- a/web/src/routes/index.svelte +++ b/web/src/routes/index.svelte @@ -4,28 +4,31 @@ import { api } from '@api'; export const load: Load = async () => { - try { - const { data: user } = await api.userApi.getMyUserInfo(); + if (browser) { + try { + const { data: user } = await api.userApi.getMyUserInfo(); + + return { + status: 302, + redirect: '/photos' + }; + } catch (e) {} + + const { data } = await api.userApi.getUserCount(); return { - status: 302, - redirect: '/photos' + status: 200, + props: { + isAdminUserExist: data.userCount == 0 ? false : true + } }; - } catch (e) {} - - const { data } = await api.userApi.getUserCount(); - - return { - status: 200, - props: { - isAdminUserExist: data.userCount == 0 ? false : true - } - }; + } }; </script> <script lang="ts"> import { goto } from '$app/navigation'; + import { browser } from '$app/env'; export let isAdminUserExist: boolean; diff --git a/web/src/routes/photos/[assetId].svelte b/web/src/routes/photos/[assetId].svelte index 0b06c70452..a1c829bf2c 100644 --- a/web/src/routes/photos/[assetId].svelte +++ b/web/src/routes/photos/[assetId].svelte @@ -1,12 +1,12 @@ <script context="module" lang="ts"> export const prerender = false; - import { api } from '@api'; import type { Load } from '@sveltejs/kit'; - export const load: Load = async () => { + export const load: Load = async ({ fetch }) => { try { - await api.userApi.getMyUserInfo(); + await fetch('/data/user/get-my-user-info'); + return { status: 302, redirect: '/photos' diff --git a/web/src/routes/photos/index.svelte b/web/src/routes/photos/index.svelte index 02b7f7f44a..e2182ac01a 100644 --- a/web/src/routes/photos/index.svelte +++ b/web/src/routes/photos/index.svelte @@ -2,20 +2,25 @@ export const prerender = false; import type { Load } from '@sveltejs/kit'; - import { getAssetsInfo } from '$lib/stores/assets'; + import { setAssetInfo } from '$lib/stores/assets'; - export const load: Load = async () => { + export const load: Load = async ({ fetch }) => { try { - const { data } = await api.userApi.getMyUserInfo(); - await getAssetsInfo(); + const [userInfo, assets] = await Promise.all([ + fetch('/data/user/get-my-user-info').then((r) => r.json()), + fetch('/data/asset/get-all-assets').then((r) => r.json()) + ]); + + setAssetInfo(assets); return { status: 200, props: { - user: data + user: userInfo } }; } catch (e) { + console.log('ERROR load photos index'); return { status: 302, redirect: '/auth/login' @@ -33,7 +38,7 @@ import moment from 'moment'; import AssetViewer from '$lib/components/asset-viewer/asset-viewer.svelte'; import { openFileUploadDialog, UploadType } from '$lib/utils/file-uploader'; - import { api, AssetResponseDto, UserResponseDto } from '@api'; + import { AssetResponseDto, UserResponseDto } from '@api'; import SideBar from '$lib/components/shared-components/side-bar/side-bar.svelte'; export let user: UserResponseDto; diff --git a/web/src/routes/sharing/index.svelte b/web/src/routes/sharing/index.svelte index 2ad725680b..4c6196e577 100644 --- a/web/src/routes/sharing/index.svelte +++ b/web/src/routes/sharing/index.svelte @@ -4,10 +4,12 @@ import type { Load } from '@sveltejs/kit'; import { AlbumResponseDto, api, UserResponseDto } from '@api'; - export const load: Load = async () => { + export const load: Load = async ({ fetch }) => { try { - const { data: user } = await api.userApi.getMyUserInfo(); - const { data: sharedAlbums } = await api.albumApi.getAllAlbums(true); + const [user, sharedAlbums] = await Promise.all([ + fetch('/data/user/get-my-user-info').then((r) => r.json()), + fetch('/data/album/get-all-albums?isShared=true').then((r) => r.json()) + ]); return { status: 200,