mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
WIP refactor container and queuing system (#206)
* refactor microservices to machine-learning * Update tGithub issue template with correct task syntax * Added microservices container * Communicate between service based on queue system * added dependency * Fixed problem with having to import BullQueue into the individual service * Added todo * refactor server into monorepo with microservices * refactor database and entity to library * added simple migration * Move migrations and database config to library * Migration works in library * Cosmetic change in logging message * added user dto * Fixed issue with testing not able to find the shared library * Clean up library mapping path * Added webp generator to microservices * Update Github Action build latest * Fixed issue NPM cannot install due to conflict witl Bull Queue * format project with prettier * Modified docker-compose file * Add GH Action for Staging build: * Fixed GH action job name * Modified GH Action to only build & push latest when pushing to main * Added Test 2e2 Github Action * Added Test 2e2 Github Action * Implemented microservice to extract exif * Added cronjob to scan and generate webp thumbnail at midnight * Refactor to ireduce hit time to database when running microservices * Added error handling to asset services that handle read file from disk * Added video transcoding queue to process one video at a time * Fixed loading spinner on web while loading covering the info panel * Add mechanism to show new release announcement to web and mobile app (#209) * Added changelog page * Fixed issues based on PR comments * Fixed issue with video transcoding run on the server * Change entry point content for backward combatibility when starting up server * Added announcement box * Added error handling to failed silently when the app version checking is not able to make the request to GITHUB * Added new version announcement overlay * Update message * Added messages * Added logic to check and show announcement * Add method to handle saving new version * Added button to dimiss the acknowledge message * Up version for deployment to the app store
This commit is contained in:
131
web/package-lock.json
generated
131
web/package-lock.json
generated
@@ -13,6 +13,7 @@
|
||||
"leaflet": "^1.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"markdown-it": "^13.0.1",
|
||||
"moment": "^2.29.3",
|
||||
"svelte-material-icons": "^2.0.2"
|
||||
},
|
||||
@@ -27,6 +28,7 @@
|
||||
"@types/leaflet": "^1.7.10",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
||||
"@typescript-eslint/parser": "^5.10.1",
|
||||
"autoprefixer": "^10.4.7",
|
||||
@@ -291,6 +293,12 @@
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
|
||||
"integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
@@ -306,6 +314,22 @@
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "12.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
|
||||
"integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/linkify-it": "*",
|
||||
"@types/mdurl": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
|
||||
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz",
|
||||
@@ -626,8 +650,7 @@
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/array-union": {
|
||||
"version": "2.1.0",
|
||||
@@ -1020,6 +1043,17 @@
|
||||
"integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-promise": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
|
||||
@@ -2078,6 +2112,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"dependencies": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@@ -2118,6 +2160,26 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.js"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -3125,6 +3187,11 @@
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -3458,6 +3525,12 @@
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"@types/linkify-it": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
|
||||
"integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
@@ -3473,6 +3546,22 @@
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"@types/markdown-it": {
|
||||
"version": "12.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
|
||||
"integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/linkify-it": "*",
|
||||
"@types/mdurl": "*"
|
||||
}
|
||||
},
|
||||
"@types/mdurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
|
||||
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz",
|
||||
@@ -3673,8 +3762,7 @@
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
@@ -3940,6 +4028,11 @@
|
||||
"integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==",
|
||||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
|
||||
@@ -4636,6 +4729,14 @@
|
||||
"integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==",
|
||||
"dev": true
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"requires": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@@ -4670,6 +4771,23 @@
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -5318,6 +5436,11 @@
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
||||
"dev": true
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
|
||||
@@ -3,58 +3,54 @@ import * as cookie from 'cookie';
|
||||
import { serverEndpoint } from '$lib/constants';
|
||||
import { session } from '$app/stores';
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
||||
|
||||
export const handle: Handle = async ({ event, resolve, }) => {
|
||||
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
||||
if (!cookies.session) {
|
||||
return await resolve(event);
|
||||
}
|
||||
|
||||
if (!cookies.session) {
|
||||
return await resolve(event)
|
||||
}
|
||||
try {
|
||||
const { email, isAdmin, firstName, lastName, id, accessToken } = JSON.parse(cookies.session);
|
||||
|
||||
try {
|
||||
const { email, isAdmin, firstName, lastName, id, accessToken } = JSON.parse(cookies.session);
|
||||
const res = await fetch(`${serverEndpoint}/auth/validateToken`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await fetch(`${serverEndpoint}/auth/validateToken`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
}
|
||||
})
|
||||
if (res.status === 201) {
|
||||
event.locals.user = {
|
||||
id,
|
||||
accessToken,
|
||||
firstName,
|
||||
lastName,
|
||||
isAdmin,
|
||||
email,
|
||||
};
|
||||
}
|
||||
|
||||
if (res.status === 201) {
|
||||
event.locals.user = {
|
||||
id,
|
||||
accessToken,
|
||||
firstName,
|
||||
lastName,
|
||||
isAdmin,
|
||||
email
|
||||
};
|
||||
}
|
||||
|
||||
const response = await resolve(event);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log('Error parsing session', error);
|
||||
return await resolve(event);
|
||||
}
|
||||
const response = await resolve(event);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log('Error parsing session', error);
|
||||
return await resolve(event);
|
||||
}
|
||||
};
|
||||
|
||||
export const getSession: GetSession = async ({ locals }) => {
|
||||
if (!locals.user) return {};
|
||||
|
||||
if (!locals.user) return {}
|
||||
|
||||
return {
|
||||
user: {
|
||||
id: locals.user.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: locals.user.firstName,
|
||||
lastName: locals.user.lastName,
|
||||
isAdmin: locals.user.isAdmin,
|
||||
email: locals.user.email
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
user: {
|
||||
id: locals.user.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: locals.user.firstName,
|
||||
lastName: locals.user.lastName,
|
||||
isAdmin: locals.user.isAdmin,
|
||||
email: locals.user.email,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,60 +1,59 @@
|
||||
import { serverEndpoint } from './constants';
|
||||
|
||||
type ISend = {
|
||||
method: string,
|
||||
path: string,
|
||||
data?: any,
|
||||
token: string
|
||||
customHeaders?: Record<string, string>,
|
||||
}
|
||||
method: string;
|
||||
path: string;
|
||||
data?: any;
|
||||
token: string;
|
||||
customHeaders?: Record<string, string>;
|
||||
};
|
||||
|
||||
type IOption = {
|
||||
method: string,
|
||||
headers: Record<string, string>,
|
||||
body: any
|
||||
|
||||
}
|
||||
method: string;
|
||||
headers: Record<string, string>;
|
||||
body: any;
|
||||
};
|
||||
|
||||
async function send({ method, path, data, token, customHeaders }: ISend) {
|
||||
const opts: IOption = { method, headers: {} } as IOption;
|
||||
const opts: IOption = { method, headers: {} } as IOption;
|
||||
|
||||
if (data) {
|
||||
opts.headers['Content-Type'] = 'application/json';
|
||||
opts.body = JSON.stringify(data);
|
||||
}
|
||||
if (data) {
|
||||
opts.headers['Content-Type'] = 'application/json';
|
||||
opts.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
if (customHeaders) {
|
||||
console.log(customHeaders);
|
||||
// opts.headers[customHeader.$1]
|
||||
}
|
||||
if (customHeaders) {
|
||||
console.log(customHeaders);
|
||||
// opts.headers[customHeader.$1]
|
||||
}
|
||||
|
||||
if (token) {
|
||||
opts.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
if (token) {
|
||||
opts.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return fetch(`${serverEndpoint}/${path}`, opts)
|
||||
.then((r) => r.text())
|
||||
.then((json) => {
|
||||
try {
|
||||
return JSON.parse(json);
|
||||
} catch (err) {
|
||||
return json;
|
||||
}
|
||||
});
|
||||
return fetch(`${serverEndpoint}/${path}`, opts)
|
||||
.then((r) => r.text())
|
||||
.then((json) => {
|
||||
try {
|
||||
return JSON.parse(json);
|
||||
} catch (err) {
|
||||
return json;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getRequest(path: string, token: string, customHeaders?: Record<string, string>) {
|
||||
return send({ method: 'GET', path, token, customHeaders });
|
||||
return send({ method: 'GET', path, token, customHeaders });
|
||||
}
|
||||
|
||||
export function delRequest(path: string, token: string, customHeaders?: Record<string, string>) {
|
||||
return send({ method: 'DELETE', path, token, customHeaders });
|
||||
return send({ method: 'DELETE', path, token, customHeaders });
|
||||
}
|
||||
|
||||
export function postRequest(path: string, data: any, token: string, customHeaders?: Record<string, string>) {
|
||||
return send({ method: 'POST', path, data, token, customHeaders });
|
||||
return send({ method: 'POST', path, data, token, customHeaders });
|
||||
}
|
||||
|
||||
export function putRequest(path: string, data: any, token: string, customHeaders?: Record<string, string>) {
|
||||
return send({ method: 'PUT', path, data, token, customHeaders });
|
||||
}
|
||||
return send({ method: 'PUT', path, data, token, customHeaders });
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
</video>
|
||||
|
||||
{#if isVideoLoading}
|
||||
<div class="absolute w-full h-full bg-black/50 flex place-items-center place-content-center">
|
||||
<div class="absolute flex place-items-center place-content-center">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
61
web/src/lib/components/shared/announcement-box.svelte
Normal file
61
web/src/lib/components/shared/announcement-box.svelte
Normal file
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import FullScreenModal from './full-screen-modal.svelte';
|
||||
export let localVersion: string;
|
||||
export let remoteVersion: string;
|
||||
|
||||
const acknowledgeClickHandler = () => {
|
||||
localStorage.setItem('appVersion', remoteVersion);
|
||||
|
||||
goto($page.url.pathname);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="absolute top-0 left-0 w-screen h-screen">
|
||||
<FullScreenModal on:clickOutside={() => console.log('Click outside')}>
|
||||
<div class="max-w-[500px] z-[99999] border bg-immich-bg p-10 rounded-xl">
|
||||
<p class="text-2xl ">🎉 NEW VERSION AVAILABLE 🎉</p>
|
||||
<br />
|
||||
|
||||
<section class="max-h-[400px] overflow-y-auto">
|
||||
<div class="font-thin">
|
||||
Hi friend, there is a new release of <span class="font-immich-title text-immich-primary font-bold"
|
||||
>IMMICH</span
|
||||
>, please take your time to visit the
|
||||
<span class="underline font-medium"
|
||||
><a href="https://github.com/alextran1502/immich/releases/latest" target="_blank" rel="noopener noreferrer"
|
||||
>release note</a
|
||||
></span
|
||||
>
|
||||
and ensure your <code>docker-compose</code>, and <code>.env</code> setup is up-to-date to prevent any misconfigurations,
|
||||
especially if you use WatchTower or any mechanism that handles updating your application automatically.
|
||||
</div>
|
||||
|
||||
{#if remoteVersion == 'v1.11.0_17-dev'}
|
||||
<div class="mt-2 font-thin">
|
||||
This specific version <span class="font-medium">v1.11.0_17-dev</span> includes changes in the docker-compose
|
||||
setup that added additional containters. Please make sure to update the docker-compose file, pull new images
|
||||
and check your setup for the latest features and bug fixes.
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<div class="font-thin mt-4">Your friend, Alex</div>
|
||||
<div class="text-xs mt-8">
|
||||
<code>Local Version {localVersion}</code>
|
||||
<br />
|
||||
<code>Remote Version {remoteVersion}</code>
|
||||
</div>
|
||||
|
||||
<div class="text-right mt-4">
|
||||
<button
|
||||
class="bg-immich-primary text-gray-50 hover:bg-immich-primary/90 py-2 px-4 rounded-lg font-medium shadow-lg transition-all"
|
||||
on:click={acknowledgeClickHandler}>Acknowledge</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</FullScreenModal>
|
||||
</div>
|
||||
@@ -11,7 +11,7 @@
|
||||
out:fade={{ duration: 100 }}
|
||||
class="absolute w-full h-full bg-black/40 z-[100] flex place-items-center place-content-center "
|
||||
>
|
||||
<div class="bg-immich-bg z-[9999] rounded-md" use:clickOutside on:outclick={() => dispatch('clickOutside')}>
|
||||
<div class="z-[9999]" use:clickOutside on:outclick={() => dispatch('clickOutside')}>
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
};
|
||||
|
||||
const navigateToAdmin = () => {
|
||||
console.log('Navigating to admin page');
|
||||
goto('/admin');
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import Cloud from 'svelte-material-icons/Cloud.svelte';
|
||||
import Dns from 'svelte-material-icons/Dns.svelte';
|
||||
import LoadingSpinner from './loading-spinner.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
type ServerInfoType = {
|
||||
diskAvailable: string;
|
||||
@@ -77,7 +78,11 @@
|
||||
<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">
|
||||
<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>
|
||||
|
||||
@@ -94,4 +99,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<hr class="ml-5 my-4" />
|
||||
</div>
|
||||
<button class="text-xs ml-5 underline hover:cursor-pointer text-immich-primary" on:click={() => goto('/changelog')}
|
||||
>Changelog</button
|
||||
> -->
|
||||
</div>
|
||||
|
||||
50
web/src/lib/utils/check-app-version.ts
Normal file
50
web/src/lib/utils/check-app-version.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
type CheckAppVersionReponse = {
|
||||
shouldShowAnnouncement: boolean;
|
||||
localVersion?: string;
|
||||
remoteVersion?: string;
|
||||
};
|
||||
|
||||
type GithubRelease = {
|
||||
tag_name: string;
|
||||
};
|
||||
|
||||
export const checkAppVersion = async (): Promise<CheckAppVersionReponse> => {
|
||||
const res = await fetch('https://api.github.com/repos/alextran1502/immich/releases/latest', {
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status == 200) {
|
||||
const latestRelease = (await res.json()) as GithubRelease;
|
||||
const appVersion = localStorage.getItem('appVersion');
|
||||
|
||||
if (!appVersion) {
|
||||
return {
|
||||
shouldShowAnnouncement: true,
|
||||
remoteVersion: latestRelease.tag_name,
|
||||
localVersion: 'empty',
|
||||
};
|
||||
}
|
||||
|
||||
if (appVersion != latestRelease.tag_name) {
|
||||
return {
|
||||
shouldShowAnnouncement: true,
|
||||
remoteVersion: latestRelease.tag_name,
|
||||
localVersion: appVersion,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
shouldShowAnnouncement: false,
|
||||
remoteVersion: latestRelease.tag_name,
|
||||
localVersion: appVersion,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
shouldShowAnnouncement: false,
|
||||
remoteVersion: '0',
|
||||
localVersion: '0',
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,19 @@
|
||||
<script context="module" lang="ts">
|
||||
import type { Load } from '@sveltejs/kit';
|
||||
import { checkAppVersion } from '$lib/utils/check-app-version';
|
||||
import { browser } from '$app/env';
|
||||
|
||||
export const load: Load = async ({ url }) => ({ props: { url } });
|
||||
export const load: Load = async ({ url }) => {
|
||||
if (browser) {
|
||||
const { shouldShowAnnouncement, localVersion, remoteVersion } = await checkAppVersion();
|
||||
|
||||
return { props: { url, shouldShowAnnouncement, localVersion, remoteVersion } };
|
||||
} else {
|
||||
return {
|
||||
props: { url },
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -10,8 +22,13 @@
|
||||
import { blur } from 'svelte/transition';
|
||||
|
||||
import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte';
|
||||
import FullScreenModal from '../lib/components/shared/full-screen-modal.svelte';
|
||||
import AnnouncementBox from '../lib/components/shared/announcement-box.svelte';
|
||||
|
||||
export let url: string;
|
||||
export let shouldShowAnnouncement: boolean;
|
||||
export let localVersion: string;
|
||||
export let remoteVersion: string;
|
||||
</script>
|
||||
|
||||
<main>
|
||||
@@ -19,6 +36,10 @@
|
||||
<div transition:blur={{ duration: 250 }}>
|
||||
<slot />
|
||||
<DownloadPanel />
|
||||
|
||||
{#if shouldShowAnnouncement}
|
||||
<AnnouncementBox {localVersion} {remoteVersion} />
|
||||
{/if}
|
||||
</div>
|
||||
{/key}
|
||||
</main>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { getRequest } from '../../../../lib/api';
|
||||
|
||||
|
||||
export const get: RequestHandler = async ({ request, locals }) => {
|
||||
const allUsers = await getRequest('user?isAll=true', locals.user!.accessToken)
|
||||
const allUsers = await getRequest('user?isAll=true', locals.user!.accessToken);
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: { allUsers }
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: { allUsers },
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { putRequest } from '../../../lib/api';
|
||||
import * as cookie from 'cookie'
|
||||
|
||||
import * as cookie from 'cookie';
|
||||
|
||||
export const post: RequestHandler = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
const form = await request.formData();
|
||||
const firstName = form.get('firstName');
|
||||
const lastName = form.get('lastName');
|
||||
|
||||
const firstName = form.get('firstName')
|
||||
const lastName = form.get('lastName')
|
||||
if (locals.user) {
|
||||
const updatedUser = await putRequest(
|
||||
'user',
|
||||
{
|
||||
id: locals.user.id,
|
||||
firstName,
|
||||
lastName,
|
||||
},
|
||||
locals.user.accessToken,
|
||||
);
|
||||
|
||||
if (locals.user) {
|
||||
const updatedUser = await putRequest('user', {
|
||||
id: locals.user.id,
|
||||
firstName,
|
||||
lastName
|
||||
}, locals.user.accessToken)
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
user: {
|
||||
id: updatedUser.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
isAdmin: updatedUser.isAdmin,
|
||||
email: updatedUser.email,
|
||||
},
|
||||
success: 'Update user success',
|
||||
},
|
||||
headers: {
|
||||
'Set-Cookie': cookie.serialize(
|
||||
'session',
|
||||
JSON.stringify({
|
||||
id: updatedUser.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
isAdmin: updatedUser.isAdmin,
|
||||
email: updatedUser.email,
|
||||
}),
|
||||
{
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
maxAge: 60 * 60 * 24 * 30,
|
||||
},
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
user: {
|
||||
id: updatedUser.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
isAdmin: updatedUser.isAdmin,
|
||||
email: updatedUser.email,
|
||||
},
|
||||
success: 'Update user success'
|
||||
},
|
||||
headers: {
|
||||
'Set-Cookie': cookie.serialize('session', JSON.stringify(
|
||||
{
|
||||
id: updatedUser.id,
|
||||
accessToken: locals.user.accessToken,
|
||||
firstName: updatedUser.firstName,
|
||||
lastName: updatedUser.lastName,
|
||||
isAdmin: updatedUser.isAdmin,
|
||||
email: updatedUser.email,
|
||||
}), {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
maxAge: 60 * 60 * 24 * 30,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
error: 'Cannot get access token from cookies'
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
error: 'Cannot get access token from cookies',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import type { Load } from '@sveltejs/kit';
|
||||
import { getAssetsInfo } from '$lib/stores/assets';
|
||||
import { checkAppVersion } from '$lib/utils/check-app-version';
|
||||
|
||||
export const load: Load = async ({ session }) => {
|
||||
if (!session.user) {
|
||||
|
||||
Reference in New Issue
Block a user