Merge branch 'main' of github.com:immich-app/immich into feat/cli-albums
This commit is contained in:
commit
afe1470965
204 changed files with 2192 additions and 3867 deletions
20
.dockerignore
Normal file
20
.dockerignore
Normal file
|
@ -0,0 +1,20 @@
|
|||
.vscode/
|
||||
cli/
|
||||
design/
|
||||
docker/
|
||||
docs/
|
||||
fastlane/
|
||||
machine-learning/
|
||||
misc/
|
||||
mobile/
|
||||
|
||||
server/node_modules
|
||||
server/coverage/
|
||||
server/.reverse-geocoding-dump/
|
||||
server/upload/
|
||||
server/dist/
|
||||
|
||||
web/node_modules/
|
||||
web/coverage/
|
||||
web/.svelte-kit
|
||||
web/build/
|
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -5,6 +5,8 @@ mobile/openapi/**/*.dart linguist-generated=true
|
|||
mobile/openapi/.openapi-generator/FILES -diff -merge
|
||||
mobile/openapi/.openapi-generator/FILES linguist-generated=true
|
||||
|
||||
mobile/lib/**/*.g.dart -diff -merge
|
||||
mobile/lib/**/*.g.dart linguist-generated=true
|
||||
|
||||
cli/src/api/open-api/**/*.md -diff -merge
|
||||
cli/src/api/open-api/**/*.md linguist-generated=true
|
||||
|
|
10
.github/workflows/docker-cleanup.yml
vendored
10
.github/workflows/docker-cleanup.yml
vendored
|
@ -29,14 +29,11 @@ jobs:
|
|||
include:
|
||||
- primary-name: "immich-server"
|
||||
- primary-name: "immich-machine-learning"
|
||||
- primary-name: "immich-web"
|
||||
- primary-name: "immich-proxy"
|
||||
env:
|
||||
# Requires a personal access token with the OAuth scope delete:packages
|
||||
TOKEN: ${{ secrets.PACKAGE_DELETE_TOKEN }}
|
||||
steps:
|
||||
-
|
||||
name: Clean temporary images
|
||||
- name: Clean temporary images
|
||||
if: "${{ env.TOKEN != '' }}"
|
||||
uses: stumpylog/image-cleaner-action/ephemeral@v0.4.0
|
||||
with:
|
||||
|
@ -60,15 +57,12 @@ jobs:
|
|||
include:
|
||||
- primary-name: "immich-server"
|
||||
- primary-name: "immich-machine-learning"
|
||||
- primary-name: "immich-web"
|
||||
- primary-name: "immich-proxy"
|
||||
- primary-name: "immich-build-cache"
|
||||
env:
|
||||
# Requires a personal access token with the OAuth scope delete:packages
|
||||
TOKEN: ${{ secrets.PACKAGE_DELETE_TOKEN }}
|
||||
steps:
|
||||
-
|
||||
name: Clean untagged images
|
||||
- name: Clean untagged images
|
||||
if: "${{ env.TOKEN != '' }}"
|
||||
uses: stumpylog/image-cleaner-action/untagged@v0.4.0
|
||||
with:
|
||||
|
|
13
.github/workflows/docker.yml
vendored
13
.github/workflows/docker.yml
vendored
|
@ -24,16 +24,12 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- context: "web"
|
||||
image: "immich-web"
|
||||
platforms: "linux/amd64,linux/arm64"
|
||||
- context: "machine-learning"
|
||||
file: "machine-learning/Dockerfile"
|
||||
image: "immich-machine-learning"
|
||||
platforms: "linux/amd64,linux/arm64"
|
||||
- context: "nginx"
|
||||
image: "immich-proxy"
|
||||
platforms: "linux/amd64,linux/arm64"
|
||||
- context: "server"
|
||||
- context: "."
|
||||
file: "server/Dockerfile"
|
||||
image: "immich-server"
|
||||
platforms: "linux/arm64,linux/amd64"
|
||||
|
||||
|
@ -100,9 +96,10 @@ jobs:
|
|||
fi
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
context: ${{ matrix.context }}
|
||||
file: ${{ matrix.file }}
|
||||
platforms: ${{ matrix.platforms }}
|
||||
# Skip pushing when PR from a fork
|
||||
push: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
|
|
5
.github/workflows/static_analysis.yml
vendored
5
.github/workflows/static_analysis.yml
vendored
|
@ -32,3 +32,8 @@ jobs:
|
|||
- name: Run dart analyze
|
||||
run: dart analyze --fatal-infos
|
||||
working-directory: ./mobile
|
||||
|
||||
# Enable after riverpod generator migration is completed
|
||||
# - name: Run dart custom lint
|
||||
# run: dart run custom_lint
|
||||
# working-directory: ./mobile
|
||||
|
|
40
cli/package-lock.json
generated
40
cli/package-lock.json
generated
|
@ -801,9 +801,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
|
||||
"integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
|
||||
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
|
@ -1583,9 +1583,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||
"version": "20.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
|
||||
"integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
|
@ -2649,15 +2649,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
|
||||
"integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
|
||||
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.3",
|
||||
"@eslint/js": "8.53.0",
|
||||
"@eslint/js": "8.54.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
|
@ -6714,9 +6714,9 @@
|
|||
}
|
||||
},
|
||||
"@eslint/js": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
|
||||
"integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
|
||||
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
|
@ -7356,9 +7356,9 @@
|
|||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||
"version": "20.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
|
||||
"integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~5.26.4"
|
||||
|
@ -8096,15 +8096,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
|
||||
"integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
|
||||
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.3",
|
||||
"@eslint/js": "8.53.0",
|
||||
"@eslint/js": "8.54.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
|
|
282
cli/src/api/open-api/api.ts
generated
282
cli/src/api/open-api/api.ts
generated
|
@ -4,7 +4,7 @@
|
|||
* Immich
|
||||
* Immich API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.86.0
|
||||
* The version of the OpenAPI document: 1.87.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
|
@ -1773,97 +1773,6 @@ export interface FileReportItemDto {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ImportAssetDto
|
||||
*/
|
||||
export interface ImportAssetDto {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'assetPath': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'deviceAssetId': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'deviceId': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'duration'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'fileCreatedAt': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'fileModifiedAt': string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isArchived'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isExternal'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isFavorite'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isOffline'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isReadOnly'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'isVisible'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'libraryId'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImportAssetDto
|
||||
*/
|
||||
'sidecarPath'?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
@ -2794,19 +2703,6 @@ export interface SearchAlbumResponseDto {
|
|||
*/
|
||||
'total': number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface SearchAssetDto
|
||||
*/
|
||||
export interface SearchAssetDto {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SearchAssetDto
|
||||
*/
|
||||
'searchTerm': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
@ -7622,50 +7518,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {ImportAssetDto} importAssetDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
importFile: async (importAssetDto: ImportAssetDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'importAssetDto' is not null or undefined
|
||||
assertParamExists('importFile', 'importAssetDto', importAssetDto)
|
||||
const localVarPath = `/asset/import`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication api_key required
|
||||
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(importAssetDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
|
@ -7792,50 +7644,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {SearchAssetDto} searchAssetDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchAsset: async (searchAssetDto: SearchAssetDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'searchAssetDto' is not null or undefined
|
||||
assertParamExists('searchAsset', 'searchAssetDto', searchAssetDto)
|
||||
const localVarPath = `/asset/search`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication api_key required
|
||||
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(searchAssetDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} [id]
|
||||
|
@ -8659,16 +8467,6 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
|||
const localVarAxiosArgs = await localVarAxiosParamCreator.getUserAssetsByDeviceId(deviceId, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {ImportAssetDto} importAssetDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async importFile(importAssetDto: ImportAssetDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.importFile(importAssetDto, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
|
@ -8698,16 +8496,6 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
|||
const localVarAxiosArgs = await localVarAxiosParamCreator.runAssetJobs(assetJobsDto, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {SearchAssetDto} searchAssetDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async searchAsset(searchAssetDto: SearchAssetDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<AssetResponseDto>>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.searchAsset(searchAssetDto, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} [id]
|
||||
|
@ -9012,15 +8800,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
|||
getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
|
||||
return localVarFp.getUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiImportFileRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
importFile(requestParameters: AssetApiImportFileRequest, options?: AxiosRequestConfig): AxiosPromise<AssetFileUploadResponseDto> {
|
||||
return localVarFp.importFile(requestParameters.importAssetDto, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiRestoreAssetsRequest} requestParameters Request parameters.
|
||||
|
@ -9047,15 +8826,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
|||
runAssetJobs(requestParameters: AssetApiRunAssetJobsRequest, options?: AxiosRequestConfig): AxiosPromise<void> {
|
||||
return localVarFp.runAssetJobs(requestParameters.assetJobsDto, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiSearchAssetRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchAsset(requestParameters: AssetApiSearchAssetRequest, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
|
||||
return localVarFp.searchAsset(requestParameters.searchAssetDto, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiSearchAssetsRequest} requestParameters Request parameters.
|
||||
|
@ -9603,20 +9373,6 @@ export interface AssetApiGetUserAssetsByDeviceIdRequest {
|
|||
readonly deviceId: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for importFile operation in AssetApi.
|
||||
* @export
|
||||
* @interface AssetApiImportFileRequest
|
||||
*/
|
||||
export interface AssetApiImportFileRequest {
|
||||
/**
|
||||
*
|
||||
* @type {ImportAssetDto}
|
||||
* @memberof AssetApiImportFile
|
||||
*/
|
||||
readonly importAssetDto: ImportAssetDto
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for restoreAssets operation in AssetApi.
|
||||
* @export
|
||||
|
@ -9645,20 +9401,6 @@ export interface AssetApiRunAssetJobsRequest {
|
|||
readonly assetJobsDto: AssetJobsDto
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for searchAsset operation in AssetApi.
|
||||
* @export
|
||||
* @interface AssetApiSearchAssetRequest
|
||||
*/
|
||||
export interface AssetApiSearchAssetRequest {
|
||||
/**
|
||||
*
|
||||
* @type {SearchAssetDto}
|
||||
* @memberof AssetApiSearchAsset
|
||||
*/
|
||||
readonly searchAssetDto: SearchAssetDto
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for searchAssets operation in AssetApi.
|
||||
* @export
|
||||
|
@ -10372,17 +10114,6 @@ export class AssetApi extends BaseAPI {
|
|||
return AssetApiFp(this.configuration).getUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiImportFileRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public importFile(requestParameters: AssetApiImportFileRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).importFile(requestParameters.importAssetDto, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiRestoreAssetsRequest} requestParameters Request parameters.
|
||||
|
@ -10415,17 +10146,6 @@ export class AssetApi extends BaseAPI {
|
|||
return AssetApiFp(this.configuration).runAssetJobs(requestParameters.assetJobsDto, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiSearchAssetRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public searchAsset(requestParameters: AssetApiSearchAssetRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).searchAsset(requestParameters.searchAssetDto, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiSearchAssetsRequest} requestParameters Request parameters.
|
||||
|
|
2
cli/src/api/open-api/base.ts
generated
2
cli/src/api/open-api/base.ts
generated
|
@ -4,7 +4,7 @@
|
|||
* Immich
|
||||
* Immich API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.86.0
|
||||
* The version of the OpenAPI document: 1.87.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
|
|
2
cli/src/api/open-api/common.ts
generated
2
cli/src/api/open-api/common.ts
generated
|
@ -4,7 +4,7 @@
|
|||
* Immich
|
||||
* Immich API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.86.0
|
||||
* The version of the OpenAPI document: 1.87.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
|
|
2
cli/src/api/open-api/configuration.ts
generated
2
cli/src/api/open-api/configuration.ts
generated
|
@ -4,7 +4,7 @@
|
|||
* Immich
|
||||
* Immich API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.86.0
|
||||
* The version of the OpenAPI document: 1.87.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
|
|
2
cli/src/api/open-api/index.ts
generated
2
cli/src/api/open-api/index.ts
generated
|
@ -4,7 +4,7 @@
|
|||
* Immich
|
||||
* Immich API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.86.0
|
||||
* The version of the OpenAPI document: 1.87.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
|
|
5
docker/README.md
Normal file
5
docker/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
> [!CAUTION]
|
||||
> Make sure to use the docker-compose.yml of the current release:
|
||||
> https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||
>
|
||||
> The compose file on main may not be compatible with the latest release.
|
|
@ -6,31 +6,34 @@ version: "3.8"
|
|||
|
||||
name: immich-dev
|
||||
|
||||
x-server-build: &server-common
|
||||
image: immich-server-dev:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
target: dev
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /usr/src/app/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1048576
|
||||
hard: 1048576
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: immich-server-dev:latest
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
target: builder
|
||||
command: npm run start:debug immich
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /usr/src/app/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
<<: *server-common
|
||||
ports:
|
||||
- 3001:3001
|
||||
- 9230:9230
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1048576
|
||||
hard: 1048576
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
@ -38,30 +41,13 @@ services:
|
|||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
image: immich-microservices:latest
|
||||
command: npm run start:debug microservices
|
||||
<<: *server-common
|
||||
# extends:
|
||||
# file: hwaccel.yml
|
||||
# service: hwaccel
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
target: builder
|
||||
command: npm run start:debug microservices
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /usr/src/app/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 9231:9230
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1048576
|
||||
hard: 1048576
|
||||
depends_on:
|
||||
- database
|
||||
- immich-server
|
||||
|
@ -73,12 +59,11 @@ services:
|
|||
build:
|
||||
context: ../web
|
||||
dockerfile: Dockerfile
|
||||
target: dev
|
||||
command: npm run dev --host
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 3000:3000
|
||||
- 2283:3000
|
||||
- 24678:24678
|
||||
volumes:
|
||||
- ../web:/usr/src/app
|
||||
|
@ -123,7 +108,7 @@ services:
|
|||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||
image: redis:6.2-alpine@sha256:80cc8518800438c684a53ed829c621c94afd1087aaeb59b0d4343ed3e7bcf6c5
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
|
@ -139,22 +124,5 @@ services:
|
|||
ports:
|
||||
- 5432:5432
|
||||
|
||||
immich-proxy:
|
||||
container_name: immich_proxy
|
||||
image: immich-proxy-dev:latest
|
||||
environment:
|
||||
# Make sure these values get passed through from the env file
|
||||
- IMMICH_SERVER_URL
|
||||
- IMMICH_WEB_URL
|
||||
build:
|
||||
context: ../nginx
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 2283:8080
|
||||
depends_on:
|
||||
- immich-server
|
||||
- immich-web
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
model-cache:
|
||||
|
|
|
@ -2,19 +2,25 @@ version: "3.8"
|
|||
|
||||
name: immich-prod
|
||||
|
||||
x-server-build: &server-common
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: immich-server:latest
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
command: [ "./start-server.sh" ]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
<<: *server-common
|
||||
ports:
|
||||
- 2283:3001
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
@ -22,35 +28,15 @@ services:
|
|||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
image: immich-microservices:latest
|
||||
command: [ "./start-microservices.sh" ]
|
||||
<<: *server-common
|
||||
# extends:
|
||||
# file: hwaccel.yml
|
||||
# service: hwaccel
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
command: [ "./start-microservices.sh" ]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
- immich-server
|
||||
- typesense
|
||||
restart: always
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
image: immich-web:latest
|
||||
build:
|
||||
context: ../web
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
depends_on:
|
||||
- immich-server
|
||||
|
||||
immich-machine-learning:
|
||||
|
@ -79,7 +65,7 @@ services:
|
|||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||
image: redis:6.2-alpine@sha256:80cc8518800438c684a53ed829c621c94afd1087aaeb59b0d4343ed3e7bcf6c5
|
||||
restart: always
|
||||
|
||||
database:
|
||||
|
@ -95,23 +81,5 @@ services:
|
|||
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
|
||||
restart: always
|
||||
|
||||
immich-proxy:
|
||||
container_name: immich_proxy
|
||||
image: immich-proxy:latest
|
||||
environment:
|
||||
# Make sure these values get passed through from the env file
|
||||
- IMMICH_SERVER_URL
|
||||
- IMMICH_WEB_URL
|
||||
build:
|
||||
context: ../nginx
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 2283:8080
|
||||
logging:
|
||||
driver: none
|
||||
depends_on:
|
||||
- immich-server
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
model-cache:
|
||||
|
|
|
@ -6,9 +6,9 @@ services:
|
|||
immich-server:
|
||||
image: immich-server-dev:latest
|
||||
build:
|
||||
context: ../server
|
||||
dockerfile: Dockerfile
|
||||
target: builder
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
target: dev
|
||||
command: npm run test:e2e
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
version: "3.8"
|
||||
|
||||
#
|
||||
# WARNING: Make sure to use the docker-compose.yml of the current release:
|
||||
#
|
||||
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||
#
|
||||
# The compose file on main may not be compatible with the latest release.
|
||||
#
|
||||
|
||||
name: immich
|
||||
|
||||
services:
|
||||
|
@ -12,6 +20,8 @@ services:
|
|||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 2283:3001
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
|
@ -45,13 +55,6 @@ services:
|
|||
- .env
|
||||
restart: always
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
image: ghcr.io/immich-app/immich-web:${IMMICH_VERSION:-release}
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
typesense:
|
||||
container_name: immich_typesense
|
||||
image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd
|
||||
|
@ -66,7 +69,7 @@ services:
|
|||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||
image: redis:6.2-alpine@sha256:80cc8518800438c684a53ed829c621c94afd1087aaeb59b0d4343ed3e7bcf6c5
|
||||
restart: always
|
||||
|
||||
database:
|
||||
|
@ -82,16 +85,6 @@ services:
|
|||
- pgdata:/var/lib/postgresql/data
|
||||
restart: always
|
||||
|
||||
immich-proxy:
|
||||
container_name: immich_proxy
|
||||
image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release}
|
||||
ports:
|
||||
- 2283:8080
|
||||
depends_on:
|
||||
- immich-server
|
||||
- immich-web
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
model-cache:
|
||||
|
|
|
@ -1,21 +1,6 @@
|
|||
# Reverse Proxy
|
||||
|
||||
When deploying Immich it is important to understand that a reverse proxy is required in front of the server and web container. The reverse proxy acts as an intermediary between the user and container, forwarding requests to the correct container based on the URL path.
|
||||
|
||||
## Default Reverse Proxy
|
||||
|
||||
Immich provides a default nginx reverse proxy preconfigured to perform the correct routing and set the necessary headers for the server and web container to use. These headers are crucial to redirect to the correct URL and determine the client's IP address.
|
||||
|
||||
## Using a Different Reverse Proxy
|
||||
|
||||
While the reverse proxy provided by Immich works well for basic deployments, some users may want to use a different reverse proxy. Fortunately, Immich is flexible enough to accommodate different reverse proxies. Users can either:
|
||||
|
||||
1. Add another reverse proxy on top of Immich's reverse proxy
|
||||
2. Completely replace the default reverse proxy
|
||||
|
||||
## Adding a Custom Reverse Proxy
|
||||
|
||||
Users can deploy a custom reverse proxy that forwards requests to Immich's reverse proxy. This way, the new reverse proxy can handle TLS termination, load balancing, or other advanced features, while still delegating routing decisions to Immich's reverse proxy. All reverse proxies between Immich and the user must forward all headers and set the `Host`, `X-Forwarded-Host`, `X-Forwarded-Proto` and `X-Forwarded-For` headers to their appropriate values. Additionally, your reverse proxy should allow for big enough uploads. By following these practices, you ensure that all custom reverse proxies are fully compatible with Immich.
|
||||
Users can deploy a custom reverse proxy that forwards requests to Immich. This way, the reverse proxy can handle TLS termination, load balancing, or other advanced features. All reverse proxies between Immich and the user must forward all headers and set the `Host`, `X-Forwarded-Host`, `X-Forwarded-Proto` and `X-Forwarded-For` headers to their appropriate values. Additionally, your reverse proxy should allow for big enough uploads. By following these practices, you ensure that all custom reverse proxies are fully compatible with Immich.
|
||||
|
||||
### Nginx example config
|
||||
|
||||
|
@ -43,7 +28,3 @@ server {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Replacing the Default Reverse Proxy
|
||||
|
||||
Replacing Immich's default reverse proxy is an advanced deployment and support may be limited. When replacing Immich's default proxy it is important to ensure that requests to `/api/*` are routed to the server container and all other requests to the web container. Additionally, the previously mentioned headers should be configured accordingly. You may find our [nginx configuration file](https://github.com/immich-app/immich/blob/main/nginx/templates/default.conf.template) a helpful reference.
|
||||
|
|
|
@ -17,6 +17,5 @@ Our [GitHub Repository](https://github.com/immich-app/immich) is a [monorepo](ht
|
|||
| `machine-learning/` | Source code for the `immich-machine-learning` docker image |
|
||||
| `misc/release/` | Scripts for version pumps and draft releases |
|
||||
| `mobile/` | Source code for the mobile app, both Android and iOS |
|
||||
| `nginx/` | Source code for the `immich-proxy` docker image |
|
||||
| `server/` | Source code for the `immich-server` docker image |
|
||||
| `web/` | Source code for the `immich-web` docker image |
|
||||
| `web/` | Source code for the `web` |
|
||||
|
|
|
@ -52,7 +52,7 @@ If you only want to do web development connected to an existing, remote backend,
|
|||
3. Start the web development server
|
||||
|
||||
```
|
||||
PUBLIC_IMMICH_SERVER_URL=https://demo.immich.app/api npm run dev
|
||||
IMMICH_SERVER_URL=https://demo.immich.app/api npm run dev
|
||||
```
|
||||
|
||||
## IDE setup
|
||||
|
@ -61,9 +61,15 @@ PUBLIC_IMMICH_SERVER_URL=https://demo.immich.app/api npm run dev
|
|||
|
||||
Setting these in the IDE give a better developer experience, auto-formatting code on save, and providing instant feedback on lint issues.
|
||||
|
||||
### Dart Code Metris
|
||||
|
||||
The mobile app uses DCM (Dart Code Metrics) for linting and metrics calculation. Please refer to the [Getting Started](https://dcm.dev/docs/getting-started/#installation) page for more information on setting up DCM
|
||||
|
||||
Note: Activating the license is not required.
|
||||
|
||||
### VSCode
|
||||
|
||||
Install `Flutter`, `Prettier`, `ESLint` and `Svelte` extensions.
|
||||
Install `Flutter`, `DCM`, `Prettier`, `ESLint` and `Svelte` extensions.
|
||||
|
||||
in User `settings.json` (`cmd + shift + p` and search for `Open User Settings JSON`) add the following:
|
||||
|
||||
|
|
|
@ -13,7 +13,3 @@ Running Immich on Windows can be frustrating and there are lots of ways it can g
|
|||
### NTFS Mounted Volumes
|
||||
|
||||
The docker-compose.dev.yml and docker-compose.prod.yml use volume mounts for the postgres database. On start-up, postgres will try to `chown` the data directory, but fail. See [this post](https://forums.docker.com/t/data-directory-var-lib-postgresql-data-pgdata-has-wrong-ownership/17963/24) for more information about this issue and possible solutions.
|
||||
|
||||
### `Cannot read properties of null (reading 'split')`
|
||||
|
||||
This error occurs when trying to access the app via port `3000` instead of `2283`. During development `immich-proxy` runs on port 2283, while `immich-web` runs on `3000`.
|
||||
|
|
|
@ -122,28 +122,6 @@ TYPESENSE_API_KEY=some-random-text
|
|||
|
||||
PUBLIC_LOGIN_PAGE_MESSAGE="My Family Photos and Videos Backup Server"
|
||||
|
||||
####################################################################################
|
||||
# Alternative Service Addresses - Optional
|
||||
#
|
||||
# This is an advanced feature for users who may be running their immich services on different hosts.
|
||||
# It will not change which address or port that services bind to within their containers, but it will change where other services look for their peers.
|
||||
# Note: immich-microservices is bound to 3002, but no references are made
|
||||
####################################################################################
|
||||
|
||||
IMMICH_WEB_URL=http://immich-web:3000
|
||||
IMMICH_SERVER_URL=http://immich-server:3001
|
||||
|
||||
####################################################################################
|
||||
# Alternative API's External Address - Optional
|
||||
#
|
||||
# This is an advanced feature used to control the public server endpoint returned to clients during Well-known discovery.
|
||||
# You should only use this if you want mobile apps to access the immich API over a custom URL. Do not include trailing slash.
|
||||
# NOTE: At this time, the web app will not be affected by this setting and will continue to use the relative path: /api
|
||||
# Examples: http://localhost:3001, http://immich-api.example.com, etc
|
||||
####################################################################################
|
||||
|
||||
#IMMICH_API_URL_EXTERNAL=http://localhost:3001
|
||||
|
||||
###################################################################################
|
||||
# Immich Version - Optional
|
||||
#
|
||||
|
|
|
@ -63,21 +63,6 @@ These environment variables are used by the `docker-compose.yml` file and do **N
|
|||
| `MACHINE_LEARNING_HOST` | Machine Learning Host | `0.0.0.0` | machine learning |
|
||||
| `MACHINE_LEARNING_PORT` | Machine Learning Port | `3003` | machine learning |
|
||||
|
||||
## URLs
|
||||
|
||||
| Variable | Description | Default | Services |
|
||||
| :------------------------- | :---------------------- | :-------------------------: | :--------- |
|
||||
| `IMMICH_WEB_URL` | Immich Web URL | `http://immich-web:3000` | proxy |
|
||||
| `IMMICH_SERVER_URL` | Immich Server URL | `http://immich-server:3001` | web, proxy |
|
||||
| `PUBLIC_IMMICH_SERVER_URL` | Public Immich URL | `http://immich-server:3001` | web |
|
||||
| `IMMICH_API_URL_EXTERNAL` | Immich API URL External | `/api` | web |
|
||||
|
||||
:::info
|
||||
|
||||
The above paths are modifying the internal paths of the containers.
|
||||
|
||||
:::
|
||||
|
||||
## Database
|
||||
|
||||
| Variable | Description | Default | Services |
|
||||
|
@ -188,19 +173,18 @@ Typesense URL example JSON before encoding:
|
|||
|
||||
| Variable | Description | Default | Services |
|
||||
| :----------------------------------------------- | :---------------------------------------------------------------- | :-----------------: | :--------------- |
|
||||
| `MACHINE_LEARNING_MODEL_TTL`<sup>\*1</sup> | Inactivity time (s) before a model is unloaded (disabled if <= 0) | `0` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if <= 0) | `300` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if <= 0) | `10` | machine learning |
|
||||
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
|
||||
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*2</sup> | Thread count of the request thread pool (disabled if <= 0) | number of CPU cores | machine learning |
|
||||
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if <= 0) | number of CPU cores | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKERS`<sup>\*3</sup> | Number of worker processes to spawn | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` | machine learning |
|
||||
|
||||
\*1: This is an experimental feature. It may result in increased memory use over time when loading models repeatedly.
|
||||
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
||||
|
||||
\*2: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
||||
|
||||
\*3: Since each process duplicates models in memory, changing this is not recommended unless you have abundant memory to go around.
|
||||
\*2: Since each process duplicates models in memory, changing this is not recommended unless you have abundant memory to go around.
|
||||
|
||||
:::info
|
||||
|
||||
|
|
|
@ -98,12 +98,12 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||
|
||||
> Note: This can take several minutes depending on your Internet speed and Unraid hardware
|
||||
|
||||
9. Once on the Docker page you will see several Immich containers, one of them will be labelled `immich_proxy` and will have a port mapping. Visit the `IP:PORT` displayed in your web browser and you should see the Immich admin setup page.
|
||||
9. Once on the Docker page you will see several Immich containers, one of them will be labelled `immich_web` and will have a port mapping. Visit the `IP:PORT` displayed in your web browser and you should see the Immich admin setup page.
|
||||
|
||||
<img
|
||||
src={require('./img/unraid06.webp').default}
|
||||
width="80%"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-proxy"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-web"
|
||||
/>
|
||||
|
||||
<details >
|
||||
|
@ -112,12 +112,12 @@ alt="Go to Docker Tab and visit the address listed next to immich-proxy"
|
|||
<img
|
||||
src={require('./img/unraid07.webp').default}
|
||||
width="80%"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-proxy"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-web"
|
||||
/>
|
||||
<img
|
||||
src={require('./img/unraid08.webp').default}
|
||||
width="90%"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-proxy"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-web"
|
||||
/>
|
||||
|
||||
</details>
|
||||
|
|
|
@ -13,7 +13,8 @@ from .schemas import ModelType
|
|||
|
||||
class Settings(BaseSettings):
|
||||
cache_folder: str = "/cache"
|
||||
model_ttl: int = 0
|
||||
model_ttl: int = 300
|
||||
model_ttl_poll_s: int = 10
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 3003
|
||||
workers: int = 1
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import asyncio
|
||||
import gc
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Any
|
||||
from zipfile import BadZipFile
|
||||
|
@ -34,7 +38,10 @@ def init_state() -> None:
|
|||
)
|
||||
# asyncio is a huge bottleneck for performance, so we use a thread pool to run blocking code
|
||||
app.state.thread_pool = ThreadPoolExecutor(settings.request_threads) if settings.request_threads > 0 else None
|
||||
app.state.locks = {model_type: threading.Lock() for model_type in ModelType}
|
||||
app.state.lock = threading.Lock()
|
||||
app.state.last_called = None
|
||||
if settings.model_ttl > 0 and settings.model_ttl_poll_s > 0:
|
||||
asyncio.ensure_future(idle_shutdown_task())
|
||||
log.info(f"Initialized request thread pool with {settings.request_threads} threads.")
|
||||
|
||||
|
||||
|
@ -79,9 +86,9 @@ async def predict(
|
|||
|
||||
|
||||
async def run(model: InferenceModel, inputs: Any) -> Any:
|
||||
app.state.last_called = time.time()
|
||||
if app.state.thread_pool is None:
|
||||
return model.predict(inputs)
|
||||
|
||||
return await asyncio.get_running_loop().run_in_executor(app.state.thread_pool, model.predict, inputs)
|
||||
|
||||
|
||||
|
@ -90,7 +97,7 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||
return model
|
||||
|
||||
def _load() -> None:
|
||||
with app.state.locks[model.model_type]:
|
||||
with app.state.lock:
|
||||
model.load()
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
|
@ -113,3 +120,27 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||
else:
|
||||
await loop.run_in_executor(app.state.thread_pool, _load)
|
||||
return model
|
||||
|
||||
|
||||
async def idle_shutdown_task() -> None:
|
||||
while True:
|
||||
log.debug("Checking for inactivity...")
|
||||
if app.state.last_called is not None and time.time() - app.state.last_called > settings.model_ttl:
|
||||
log.info("Shutting down due to inactivity.")
|
||||
loop = asyncio.get_running_loop()
|
||||
for task in asyncio.all_tasks(loop):
|
||||
if task is not asyncio.current_task():
|
||||
try:
|
||||
task.cancel()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
sys.stderr.close()
|
||||
sys.stdout.close()
|
||||
sys.stdout = sys.stderr = open(os.devnull, "w")
|
||||
try:
|
||||
await app.state.model_cache.cache.clear()
|
||||
gc.collect()
|
||||
loop.stop()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
await asyncio.sleep(settings.model_ttl_poll_s)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "machine-learning"
|
||||
version = "1.86.0"
|
||||
version = "1.87.0"
|
||||
description = ""
|
||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
|
|
@ -36,3 +36,58 @@ analyzer:
|
|||
- openapi/
|
||||
- openapi/test/
|
||||
- lib/generated_plugin_registrant.dart
|
||||
|
||||
plugins:
|
||||
- custom_lint
|
||||
|
||||
dart_code_metrics:
|
||||
metrics:
|
||||
cyclomatic-complexity: 20
|
||||
number-of-parameters: 4
|
||||
maximum-nesting-level: 5
|
||||
rules:
|
||||
# Common
|
||||
- avoid-accessing-collections-by-constant-index
|
||||
- avoid-accessing-other-classes-private-members
|
||||
- avoid-async-call-in-sync-function
|
||||
- avoid-cascade-after-if-null
|
||||
- avoid-collapsible-if
|
||||
- avoid-collection-methods-with-unrelated-types
|
||||
- avoid-declaring-call-method
|
||||
- avoid-double-slash-imports
|
||||
- avoid-duplicate-cascades
|
||||
- avoid-duplicate-patterns
|
||||
- avoid-generics-shadowing
|
||||
- avoid-global-state
|
||||
# Flutter
|
||||
- add-copy-with:
|
||||
file-name-pattern: '.model.dart'
|
||||
- always-remove-listener
|
||||
- avoid-border-all
|
||||
- avoid-empty-setstate
|
||||
- avoid-expanded-as-spacer
|
||||
- avoid-incomplete-copy-with
|
||||
- avoid-inherited-widget-in-initstate
|
||||
- avoid-late-context
|
||||
- avoid-recursive-widget-calls
|
||||
- avoid-returning-widgets
|
||||
- avoid-shrink-wrap-in-lists
|
||||
- avoid-single-child-column-or-row
|
||||
- avoid-state-constructors
|
||||
- avoid-stateless-widget-initialized-fields
|
||||
- avoid-unnecessary-overrides-in-state
|
||||
- avoid-unnecessary-stateful-widgets
|
||||
- avoid-wrapping-in-padding
|
||||
- dispose-fields
|
||||
- prefer-const-border-radius
|
||||
- prefer-correct-edge-insets-constructor
|
||||
- prefer-dedicated-media-query-methods
|
||||
- prefer-define-hero-tag
|
||||
- prefer-extracting-callbacks
|
||||
- prefer-single-widget-per-file:
|
||||
ignore-private-widgets: true
|
||||
- prefer-sliver-prefix
|
||||
- prefer-text-rich
|
||||
- prefer-using-list-view
|
||||
- proper-super-calls
|
||||
- use-setstate-synchronously
|
||||
|
|
|
@ -35,8 +35,8 @@ platform :android do
|
|||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 110,
|
||||
"android.injected.version.name" => "1.86.0",
|
||||
"android.injected.version.code" => 111,
|
||||
"android.injected.version.name" => "1.87.0",
|
||||
}
|
||||
)
|
||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000218">
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000219">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="65.551055">
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="67.071569">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="31.674724">
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="29.991184">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||
"advanced_settings_log_level_title": "Log level: {}",
|
||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||
|
@ -106,6 +107,9 @@
|
|||
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
|
||||
"cache_settings_clear_cache_button": "Clear cache",
|
||||
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
|
||||
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
||||
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
||||
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
||||
"cache_settings_image_cache_size": "Image cache size ({} assets)",
|
||||
"cache_settings_statistics_album": "Library thumbnails",
|
||||
"cache_settings_statistics_assets": "{} assets ({})",
|
||||
|
@ -195,6 +199,7 @@
|
|||
"library_page_sort_title": "Album title",
|
||||
"login_disabled": "Login has been disabled",
|
||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||
"login_form_back_button_text": "Back",
|
||||
"login_form_button_text": "Login",
|
||||
"login_form_email_hint": "youremail@email.com",
|
||||
"login_form_endpoint_hint": "http://your-server-ip:port/api",
|
||||
|
@ -217,6 +222,10 @@
|
|||
"login_form_server_error": "Could not connect to server.",
|
||||
"login_password_changed_error": "There was an error updating your password",
|
||||
"login_password_changed_success": "Password updated successfully",
|
||||
"map_assets_in_bounds": {
|
||||
"one": "{} photo",
|
||||
"many": "{} photos"
|
||||
},
|
||||
"map_cannot_get_user_location": "Cannot get user's location",
|
||||
"map_location_dialog_cancel": "Cancel",
|
||||
"map_location_dialog_yes": "Yes",
|
||||
|
@ -226,6 +235,15 @@
|
|||
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
||||
"map_no_location_permission_title": "Location Permission denied",
|
||||
"map_settings_dark_mode": "Dark mode",
|
||||
"map_settings_date_range_option_all": "All",
|
||||
"map_settings_date_range_option_days": {
|
||||
"one": "Past 24 hours",
|
||||
"other": "Past {} days"
|
||||
},
|
||||
"map_settings_date_range_option_years": {
|
||||
"one": "Past year",
|
||||
"other": "Past {} years"
|
||||
},
|
||||
"map_settings_dialog_cancel": "Cancel",
|
||||
"map_settings_dialog_save": "Save",
|
||||
"map_settings_dialog_title": "Map Settings",
|
||||
|
@ -261,9 +279,13 @@
|
|||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||
"profile_drawer_app_logs": "Logs",
|
||||
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
||||
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
||||
"profile_drawer_client_server_up_to_date": "Client and Server are up-to-date",
|
||||
"profile_drawer_documentation": "Documentation",
|
||||
"profile_drawer_github": "GitHub",
|
||||
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
||||
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
||||
"profile_drawer_settings": "Settings",
|
||||
"profile_drawer_sign_out": "Sign Out",
|
||||
"profile_drawer_trash": "Trash",
|
||||
|
@ -275,6 +297,13 @@
|
|||
"search_page_no_objects": "No Objects Info Available",
|
||||
"search_page_no_places": "No Places Info Available",
|
||||
"search_page_people": "People",
|
||||
"search_page_person_add_name_dialog_cancel": "Cancel",
|
||||
"search_page_person_add_name_dialog_save": "Save",
|
||||
"search_page_person_add_name_dialog_hint": "Name",
|
||||
"search_page_person_add_name_dialog_title": "Add a name",
|
||||
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
||||
"search_page_person_add_name_title": "Add a name",
|
||||
"search_page_person_edit_name": "Edit name",
|
||||
"search_page_places": "Places",
|
||||
"search_page_recently_added": "Recently added",
|
||||
"search_page_screenshots": "Screenshots",
|
||||
|
@ -283,6 +312,7 @@
|
|||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "View all",
|
||||
"search_page_your_activity": "Your activity",
|
||||
"search_page_your_map": "Your Map",
|
||||
"search_result_page_new_search_hint": "New Search",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||
|
@ -292,6 +322,7 @@
|
|||
"server_info_box_app_version": "App Version",
|
||||
"server_info_box_server_url": "Server URL",
|
||||
"server_info_box_server_version": "Server Version",
|
||||
"server_info_box_latest_release":"Latest Version",
|
||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
||||
"setting_image_viewer_original_title": "Load original image",
|
||||
|
@ -321,9 +352,17 @@
|
|||
"shared_album_activity_remove_title": "Delete Activity",
|
||||
"shared_album_activity_setting_subtitle": "Let others respond",
|
||||
"shared_album_activity_setting_title": "Comments & likes",
|
||||
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
||||
"shared_album_section_people_action_leave": "Remove user from album",
|
||||
"shared_album_section_people_action_remove_user": "Remove user from album",
|
||||
"shared_album_section_people_owner_label": "Owner",
|
||||
"shared_album_section_people_title": "PEOPLE",
|
||||
"share_dialog_preparing": "Preparing...",
|
||||
"shared_link_app_bar_title": "Shared Links",
|
||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
||||
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
||||
"shared_link_create_app_bar_title": "Create link to share",
|
||||
"shared_link_create_error": "Error while creating shared link",
|
||||
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
||||
"shared_link_create_submit_button": "Create link",
|
||||
"shared_link_edit_allow_download": "Allow public user to download",
|
||||
|
@ -333,6 +372,19 @@
|
|||
"shared_link_edit_description": "Description",
|
||||
"shared_link_edit_description_hint": "Enter the share description",
|
||||
"shared_link_edit_expire_after": "Expire after",
|
||||
"shared_link_edit_expire_after_option_days": {
|
||||
"one": "{} day",
|
||||
"other": "{} days"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_hours": {
|
||||
"one": "{} hour",
|
||||
"other": "{} hours"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_minutes": {
|
||||
"one": "{} minute",
|
||||
"other": "{} minutes"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_never": "Never",
|
||||
"shared_link_edit_password": "Password",
|
||||
"shared_link_edit_password_hint": "Enter the share password",
|
||||
"shared_link_edit_show_meta": "Show metadata",
|
||||
|
@ -386,5 +438,6 @@
|
|||
"version_announcement_overlay_title": "New Server Version Available \uD83C\uDF89",
|
||||
"viewer_remove_from_stack": "Remove from Stack",
|
||||
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
||||
"viewer_unstack": "Un-Stack"
|
||||
}
|
||||
"viewer_unstack": "Un-Stack",
|
||||
"scaffold_body_error_occured": "Error occured"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"add_to_album_bottom_sheet_added": "Agregado a {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Ya se encuentra en {album}",
|
||||
"advanced_settings_log_level_title": "Nivel de registro: {}",
|
||||
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
||||
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
||||
"advanced_settings_self_signed_ssl_subtitle": "Omite la verificación del certificado SSL para la URL del servidor. Requerido para certificados autofirmados.",
|
||||
|
@ -106,6 +107,9 @@
|
|||
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} recursos)",
|
||||
"cache_settings_clear_cache_button": "Borrar caché",
|
||||
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
|
||||
"cache_settings_duplicated_assets_clear_button": "BORRAR",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotos y videos que son ignorados por la aplicación",
|
||||
"cache_settings_duplicated_assets_title": "Recursos duplicados ({})",
|
||||
"cache_settings_image_cache_size": "Tamaño de la caché de imágenes ({} recursos)",
|
||||
"cache_settings_statistics_album": "Miniaturas de la biblioteca",
|
||||
"cache_settings_statistics_assets": "{} recursos ({})",
|
||||
|
@ -174,6 +178,7 @@
|
|||
"home_page_building_timeline": "Construyendo la línea de tiempo",
|
||||
"home_page_favorite_err_local": "Aún no se pueden marcar recursos locales como favoritos, omitiendo",
|
||||
"home_page_first_time_notice": "Si ésta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
|
||||
"home_page_share_err_local": "No se pueden compartir recursos locales a través de enlaces, omitiendo",
|
||||
"home_page_upload_err_limit": "Sólo se pueden subir un máximo de 30 recursos a la vez, omitiendo",
|
||||
"home_page_favorite_err_partner": "Aún no se pueden marcar recursos de compañeros como favoritos, omitiendo",
|
||||
"home_page_album_err_partner": "Aún no se pueden agregar recursos de compañeros a un álbum, omitiendo",
|
||||
|
@ -194,6 +199,7 @@
|
|||
"library_page_sort_title": "Título del álbum",
|
||||
"login_disabled": "El inicio de sesión ha sido deshabilitado",
|
||||
"login_form_api_exception": "Excepción de API. Por favor, verifica la URL del servidor e inténtalo de nuevo.",
|
||||
"login_form_back_button_text": "Volver",
|
||||
"login_form_button_text": "Iniciar sesión",
|
||||
"login_form_email_hint": "tucorreo@correo.com",
|
||||
"login_form_endpoint_hint": "http://ip-de-tu-servidor:puerto/api",
|
||||
|
@ -216,6 +222,10 @@
|
|||
"login_form_server_error": "No se pudo conectar al servidor.",
|
||||
"login_password_changed_error": "Hubo un error al actualizar tu contraseña",
|
||||
"login_password_changed_success": "Contraseña actualizada exitosamente",
|
||||
"map_assets_in_bounds": {
|
||||
"one": "{} foto",
|
||||
"other": "{} fotos"
|
||||
},
|
||||
"map_cannot_get_user_location": "No se puede obtener la ubicación del usuario",
|
||||
"map_location_dialog_cancel": "Cancelar",
|
||||
"map_location_dialog_yes": "Sí",
|
||||
|
@ -225,6 +235,15 @@
|
|||
"map_no_location_permission_content": "Se necesita permiso de ubicación para mostrar recursos desde tu ubicación actual. ¿Quieres permitirlo ahora?",
|
||||
"map_no_location_permission_title": "Permiso de ubicación denegado",
|
||||
"map_settings_dark_mode": "Modo oscuro",
|
||||
"map_settings_date_range_option_all": "Todo",
|
||||
"map_settings_date_range_option_days": {
|
||||
"one": "Últimas 24 horas",
|
||||
"other": "Últimos {} días"
|
||||
},
|
||||
"map_settings_date_range_option_years": {
|
||||
"one": "Último año",
|
||||
"other": "Últimos {} años"
|
||||
},
|
||||
"map_settings_dialog_cancel": "Cancelar",
|
||||
"map_settings_dialog_save": "Guardar",
|
||||
"map_settings_dialog_title": "Configuración del mapa",
|
||||
|
@ -249,6 +268,7 @@
|
|||
"partner_page_stop_sharing_content": "{} ya no podrá acceder a tus fotos",
|
||||
"partner_page_stop_sharing_title": "¿Dejar de compartir tus fotos?",
|
||||
"partner_page_title": "Compañero",
|
||||
"permission_onboarding_back": "Volver",
|
||||
"permission_onboarding_continue_anyway": "Continuar de todos modos",
|
||||
"permission_onboarding_get_started": "Empezar",
|
||||
"permission_onboarding_go_to_settings": "Ir a configuración",
|
||||
|
@ -259,9 +279,13 @@
|
|||
"permission_onboarding_permission_limited": "Permiso limitado. Para permitir que Immich haga copia de seguridad y gestione toda tu colección de galería, concede permisos de fotos y videos en Configuración.",
|
||||
"permission_onboarding_request": "Immich requiere permiso para ver tus fotos y videos.",
|
||||
"profile_drawer_app_logs": "Registros",
|
||||
"profile_drawer_client_out_of_date_major": "La aplicación móvil está desactualizada. Actualiza a la última versión mayor.",
|
||||
"profile_drawer_client_out_of_date_minor": "La aplicación móvil está desactualizada. Actualiza a la última versión menor.",
|
||||
"profile_drawer_client_server_up_to_date": "El cliente y el servidor están actualizados",
|
||||
"profile_drawer_documentation": "Documentación",
|
||||
"profile_drawer_github": "GitHub",
|
||||
"profile_drawer_server_out_of_date_major": "El servidor está desactualizado. Actualiza a la última versión mayor.",
|
||||
"profile_drawer_server_out_of_date_minor": "El servidor está desactualizado. Actualiza a la última versión menor.",
|
||||
"profile_drawer_settings": "Configuración",
|
||||
"profile_drawer_sign_out": "Cerrar sesión",
|
||||
"profile_drawer_trash": "Papelera",
|
||||
|
@ -269,10 +293,17 @@
|
|||
"search_bar_hint": "Busca tus fotos",
|
||||
"search_page_categories": "Categorías",
|
||||
"search_page_favorites": "Favoritos",
|
||||
"search_page_motion_photos": "Fotos en .ovimiento",
|
||||
"search_page_motion_photos": "Fotos en movimiento",
|
||||
"search_page_no_objects": "No hay información de objetos disponible",
|
||||
"search_page_no_places": "No hay información de lugares disponible",
|
||||
"search_page_people": "Personas",
|
||||
"search_page_person_add_name_dialog_cancel": "Cancelar",
|
||||
"search_page_person_add_name_dialog_hint": "Nombre",
|
||||
"search_page_person_add_name_dialog_save": "Guardar",
|
||||
"search_page_person_add_name_dialog_title": "Agregar nombre",
|
||||
"search_page_person_add_name_subtitle": "Encuéntralos rápidamente por nombre",
|
||||
"search_page_person_add_name_title": "Agregar un nombre",
|
||||
"search_page_person_edit_name": "Editar nombre",
|
||||
"search_page_places": "Lugares",
|
||||
"search_page_recently_added": "Recién agregados",
|
||||
"search_page_screenshots": "Capturas de pantalla",
|
||||
|
@ -281,6 +312,7 @@
|
|||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "Ver todo",
|
||||
"search_page_your_activity": "Tu actividad",
|
||||
"search_page_your_map": "Tu mapa",
|
||||
"search_result_page_new_search_hint": "Nueva búsqueda",
|
||||
"search_suggestion_list_smart_search_hint_1": "La búsqueda inteligente está habilitada por defecto, para buscar metadatos utiliza la sintaxis ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:tu-término-de-búsqueda",
|
||||
|
@ -290,6 +322,7 @@
|
|||
"server_info_box_app_version": "Versión de la Aplicación",
|
||||
"server_info_box_server_url": "URL del Servidor",
|
||||
"server_info_box_server_version": "Versión del Servidor",
|
||||
"server_info_box_latest_release": "Última versión",
|
||||
"setting_image_viewer_help": "El visor de detalles carga primero la miniatura pequeña, luego carga la vista previa de tamaño mediano (si está habilitada), finalmente carga la original (si está habilitada).",
|
||||
"setting_image_viewer_original_subtitle": "Activar para cargar la imagen en resolución original (¡muy grande!). Deshabilitar para reducir el consumo de datos (de red y caché).",
|
||||
"setting_image_viewer_original_title": "Cargar imagen original",
|
||||
|
@ -319,9 +352,17 @@
|
|||
"shared_album_activity_remove_title": "Eliminar actividad",
|
||||
"shared_album_activity_setting_subtitle": "Permitir que otros respondan",
|
||||
"shared_album_activity_setting_title": "Comentarios y me gusta",
|
||||
"shared_album_section_people_action_error": "Error al dejar/remover del álbum",
|
||||
"shared_album_section_people_action_leave": "Dejar álbum",
|
||||
"shared_album_section_people_action_remove_user": "Remover usuario del álbum",
|
||||
"shared_album_section_people_owner_label": "Dueño",
|
||||
"shared_album_section_people_title": "PERSONAS",
|
||||
"share_dialog_preparing": "Preparando...",
|
||||
"shared_link_app_bar_title": "Enlaces compartidos",
|
||||
"shared_link_clipboard_copied_massage": "Copiado al portapapeles",
|
||||
"shared_link_clipboard_text": "Enlace: {}\nContraseña: {}",
|
||||
"shared_link_create_app_bar_title": "Crear enlace para compartir",
|
||||
"shared_link_create_error": "Error al crear enlace compartido",
|
||||
"shared_link_create_info": "Permitir que cualquiera con el enlace vea la(s) foto(s) seleccionada(s)",
|
||||
"shared_link_create_submit_button": "Crear enlace",
|
||||
"shared_link_edit_allow_download": "Permitir que el usuario público pueda descargar",
|
||||
|
@ -331,6 +372,19 @@
|
|||
"shared_link_edit_description": "Descripción",
|
||||
"shared_link_edit_description_hint": "Introduce la descripción del enlace",
|
||||
"shared_link_edit_expire_after": "Expirar después de",
|
||||
"shared_link_edit_expire_after_option_days": {
|
||||
"one": "{} día",
|
||||
"other": "{} días"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_hours": {
|
||||
"one": "{} hora",
|
||||
"other": "{} horas"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_minutes": {
|
||||
"one": "{} minuto",
|
||||
"other": "{} minutos"
|
||||
},
|
||||
"shared_link_edit_expire_after_option_never": "Nunca",
|
||||
"shared_link_edit_password": "Contraseña",
|
||||
"shared_link_edit_password_hint": "Introduce la contraseña del enlace",
|
||||
"shared_link_edit_show_meta": "Mostrar metadatos",
|
||||
|
|
|
@ -2,7 +2,9 @@ import 'dart:async';
|
|||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
|
@ -40,7 +42,12 @@ class ImmichTestHelper {
|
|||
await Store.clear();
|
||||
await db.writeTxn(() => db.clear());
|
||||
// Load main Widget
|
||||
await tester.pumpWidget(app.getMainWidget(db));
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [dbProvider.overrideWithValue(db)],
|
||||
child: app.getMainWidget(),
|
||||
),
|
||||
);
|
||||
// Post run tasks
|
||||
await EasyLocalization.ensureInitialized();
|
||||
}
|
||||
|
|
|
@ -379,7 +379,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 126;
|
||||
CURRENT_PROJECT_VERSION = 127;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
@ -515,7 +515,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 126;
|
||||
CURRENT_PROJECT_VERSION = 127;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
@ -543,7 +543,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 126;
|
||||
CURRENT_PROJECT_VERSION = 127;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
|
@ -54,11 +54,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.86.0</string>
|
||||
<string>1.87.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>126</string>
|
||||
<string>127</string>
|
||||
<key>FLTEnableImpeller</key>
|
||||
<true />
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
|
|
|
@ -19,7 +19,7 @@ platform :ios do
|
|||
desc "iOS Beta"
|
||||
lane :beta do
|
||||
increment_version_number(
|
||||
version_number: "1.86.0"
|
||||
version_number: "1.87.0"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
|
|
@ -5,32 +5,32 @@
|
|||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000247">
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000245">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.168149">
|
||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.162192">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="8.849255">
|
||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="5.082136">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.190436">
|
||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.181105">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="4: build_app" time="130.972743">
|
||||
<testcase classname="fastlane.lanes" name="4: build_app" time="99.633247">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="56.94492">
|
||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="62.690406">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
|
27
mobile/lib/extensions/asyncvalue_extensions.dart
Normal file
27
mobile/lib/extensions/asyncvalue_extensions.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
extension ScaffoldBody<T> on AsyncValue<T> {
|
||||
static final Logger _scaffoldBodyLog = Logger("ScaffoldBody");
|
||||
|
||||
Widget scaffoldBodyWhen({
|
||||
required Widget Function(T data) onData,
|
||||
Widget? onError,
|
||||
}) {
|
||||
if (isLoading) {
|
||||
return const Center(
|
||||
child: ImmichLoadingIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (hasError && !hasValue) {
|
||||
_scaffoldBodyLog.severe("Error occured in AsyncValue", error, stackTrace);
|
||||
return onError ?? const ScaffoldErrorBody();
|
||||
}
|
||||
|
||||
return onData(requireValue);
|
||||
}
|
||||
}
|
|
@ -26,11 +26,9 @@ import 'package:immich_mobile/shared/models/store.dart';
|
|||
import 'package:immich_mobile/shared/models/user.dart';
|
||||
import 'package:immich_mobile/shared/providers/app_state.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/release_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/services/immich_logger.service.dart';
|
||||
import 'package:immich_mobile/shared/services/local_notification.service.dart';
|
||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
||||
import 'package:immich_mobile/shared/views/version_announcement_overlay.dart';
|
||||
import 'package:immich_mobile/utils/http_ssl_cert_override.dart';
|
||||
import 'package:immich_mobile/utils/immich_app_theme.dart';
|
||||
import 'package:immich_mobile/utils/migration.dart';
|
||||
|
@ -45,7 +43,12 @@ void main() async {
|
|||
await initApp();
|
||||
await migrateDatabaseIfNeeded(db);
|
||||
HttpOverrides.global = HttpSSLCertOverride();
|
||||
runApp(getMainWidget(db));
|
||||
runApp(
|
||||
ProviderScope(
|
||||
overrides: [dbProvider.overrideWithValue(db)],
|
||||
child: getMainWidget(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initApp() async {
|
||||
|
@ -105,16 +108,13 @@ Future<Isar> loadDb() async {
|
|||
return db;
|
||||
}
|
||||
|
||||
Widget getMainWidget(Isar db) {
|
||||
Widget getMainWidget() {
|
||||
return EasyLocalization(
|
||||
supportedLocales: locales,
|
||||
path: translationsPath,
|
||||
useFallbackTranslations: true,
|
||||
fallbackLocale: locales.first,
|
||||
child: ProviderScope(
|
||||
overrides: [dbProvider.overrideWithValue(db)],
|
||||
child: const ImmichApp(),
|
||||
),
|
||||
child: const ImmichApp(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,6 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var router = ref.watch(appRouterProvider);
|
||||
ref.watch(releaseInfoProvider.notifier).checkGithubReleaseInfo();
|
||||
|
||||
return MaterialApp(
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
|
@ -217,7 +216,6 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
|||
),
|
||||
),
|
||||
const ImmichLoadingOverlay(),
|
||||
const VersionAnnouncementOverlay(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -188,7 +188,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
context.pop();
|
||||
buildContext.pop();
|
||||
},
|
||||
);
|
||||
return const ShareDialog();
|
||||
|
|
|
@ -30,7 +30,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||
Navigator.pop(context);
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: "Error leaving/removing from album",
|
||||
msg: "shared_album_section_people_action_error".tr(),
|
||||
toastType: ToastType.error,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||
actions = [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.exit_to_app_rounded),
|
||||
title: const Text("Leave album"),
|
||||
title: const Text("shared_album_section_people_action_leave").tr(),
|
||||
onTap: leaveAlbum,
|
||||
),
|
||||
];
|
||||
|
@ -91,7 +91,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||
actions = [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.person_remove_rounded),
|
||||
title: const Text("Remove user from album"),
|
||||
title: const Text("shared_album_section_people_remove_user").tr(),
|
||||
onTap: () => removeUserFromAlbum(user),
|
||||
),
|
||||
];
|
||||
|
@ -130,11 +130,11 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||
style: TextStyle(color: Colors.grey[500]),
|
||||
),
|
||||
trailing: const Text(
|
||||
"Owner",
|
||||
"shared_album_section_people_owner_label",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
).tr(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||
subtitle:
|
||||
const Text("shared_album_activity_setting_subtitle").tr(),
|
||||
),
|
||||
buildSectionTitle("PEOPLE"),
|
||||
buildSectionTitle("shared_album_section_people_title".tr()),
|
||||
buildOwnerInfo(),
|
||||
buildSharedUsersList(),
|
||||
],
|
||||
|
|
|
@ -68,7 +68,7 @@ class ImageViewerStateNotifier extends StateNotifier<ImageViewerPageState> {
|
|||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
context.pop();
|
||||
buildContext.pop();
|
||||
},
|
||||
);
|
||||
return const ShareDialog();
|
||||
|
|
|
@ -358,7 +358,7 @@ class LoginForm extends HookConsumerWidget {
|
|||
TextButton.icon(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => serverEndpoint.value = null,
|
||||
label: const Text('Back'),
|
||||
label: const Text('login_form_back_button_text').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -176,7 +176,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||
|
||||
Widget buildDragHandle(ScrollController scrollController) {
|
||||
final textToDisplay = assetsInBound.value.isNotEmpty
|
||||
? "${assetsInBound.value.length} photo${assetsInBound.value.length > 1 ? "s" : ""}"
|
||||
? "map_assets_in_bounds".plural(assetsInBound.value.length)
|
||||
: "map_no_assets_in_bounds".tr();
|
||||
final dragHandle = Container(
|
||||
height: 60,
|
||||
|
|
|
@ -76,18 +76,21 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||
showRelativeDate.value = value!;
|
||||
},
|
||||
dropdownMenuEntries: [
|
||||
const DropdownMenuEntry(value: 0, label: "All"),
|
||||
const DropdownMenuEntry(
|
||||
DropdownMenuEntry(
|
||||
value: 0,
|
||||
label: "map_settings_date_range_option_all".tr(),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 1,
|
||||
label: "Past 24 hours",
|
||||
label: "map_settings_date_range_option_days".plural(1),
|
||||
),
|
||||
const DropdownMenuEntry(
|
||||
DropdownMenuEntry(
|
||||
value: 7,
|
||||
label: "Past 7 days",
|
||||
label: "map_settings_date_range_option_days".plural(7),
|
||||
),
|
||||
const DropdownMenuEntry(
|
||||
DropdownMenuEntry(
|
||||
value: 30,
|
||||
label: "Past 30 days",
|
||||
label: "map_settings_date_range_option_days".plural(30),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: now
|
||||
|
@ -102,7 +105,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||
),
|
||||
)
|
||||
.inDays,
|
||||
label: "Past year",
|
||||
label: "map_settings_date_range_option_years".plural(1),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: now
|
||||
|
@ -117,7 +120,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||
),
|
||||
)
|
||||
.inDays,
|
||||
label: "Past 3 years",
|
||||
label: "map_settings_date_range_option_years".plural(3),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,44 +1,51 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
||||
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
||||
import 'package:immich_mobile/modules/search/services/person.service.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
final personAssetsProvider = FutureProvider.family
|
||||
.autoDispose<RenderList, String>((ref, personId) async {
|
||||
final PersonService personService = ref.watch(personServiceProvider);
|
||||
part 'people.provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<List<CuratedContent>> getCuratedPeople(
|
||||
GetCuratedPeopleRef ref,
|
||||
) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
|
||||
final curatedPeople = await personService.getCuratedPeople();
|
||||
|
||||
return curatedPeople
|
||||
.map((p) => CuratedContent(id: p.id, label: p.name))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<RenderList> personAssets(PersonAssetsRef ref, String personId) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
final assets = await personService.getPersonAssets(personId);
|
||||
|
||||
if (assets == null) {
|
||||
return RenderList.empty();
|
||||
}
|
||||
|
||||
return RenderList.fromAssets(assets, GroupAssetsBy.auto);
|
||||
});
|
||||
|
||||
final getCuratedPeopleProvider =
|
||||
FutureProvider.autoDispose<List<PersonResponseDto>>((ref) async {
|
||||
final PersonService personService = ref.watch(personServiceProvider);
|
||||
|
||||
final curatedPeople = await personService.getCuratedPeople();
|
||||
|
||||
return curatedPeople ?? [];
|
||||
});
|
||||
|
||||
class UpdatePersonName {
|
||||
final String id;
|
||||
final String name;
|
||||
|
||||
UpdatePersonName(this.id, this.name);
|
||||
final settings = ref.read(appSettingsServiceProvider);
|
||||
final groupBy =
|
||||
GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)];
|
||||
return await RenderList.fromAssets(assets, groupBy);
|
||||
}
|
||||
|
||||
final updatePersonNameProvider =
|
||||
StateProvider.family<void, UpdatePersonName>((ref, dto) async {
|
||||
final PersonService personService = ref.watch(personServiceProvider);
|
||||
@riverpod
|
||||
Future<bool> updatePersonName(
|
||||
UpdatePersonNameRef ref,
|
||||
String personId,
|
||||
String updatedName,
|
||||
) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
final person = await personService.updateName(personId, updatedName);
|
||||
|
||||
final person = await personService.updateName(dto.id, dto.name);
|
||||
|
||||
if (person != null && person.name == dto.name) {
|
||||
if (person != null && person.name == updatedName) {
|
||||
ref.invalidate(getCuratedPeopleProvider);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
|
320
mobile/lib/modules/search/providers/people.provider.g.dart
generated
Normal file
320
mobile/lib/modules/search/providers/people.provider.g.dart
generated
Normal file
|
@ -0,0 +1,320 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'people.provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getCuratedPeopleHash() => r'2a534553812abe69abce2c2e41aa62b8de16e9d0';
|
||||
|
||||
/// See also [getCuratedPeople].
|
||||
@ProviderFor(getCuratedPeople)
|
||||
final getCuratedPeopleProvider =
|
||||
AutoDisposeFutureProvider<List<CuratedContent>>.internal(
|
||||
getCuratedPeople,
|
||||
name: r'getCuratedPeopleProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getCuratedPeopleHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef GetCuratedPeopleRef
|
||||
= AutoDisposeFutureProviderRef<List<CuratedContent>>;
|
||||
String _$personAssetsHash() => r'1d6eff5ca3aa630b58c4dad9516193b21896984d';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [personAssets].
|
||||
@ProviderFor(personAssets)
|
||||
const personAssetsProvider = PersonAssetsFamily();
|
||||
|
||||
/// See also [personAssets].
|
||||
class PersonAssetsFamily extends Family<AsyncValue<RenderList>> {
|
||||
/// See also [personAssets].
|
||||
const PersonAssetsFamily();
|
||||
|
||||
/// See also [personAssets].
|
||||
PersonAssetsProvider call(
|
||||
String personId,
|
||||
) {
|
||||
return PersonAssetsProvider(
|
||||
personId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
PersonAssetsProvider getProviderOverride(
|
||||
covariant PersonAssetsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.personId,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'personAssetsProvider';
|
||||
}
|
||||
|
||||
/// See also [personAssets].
|
||||
class PersonAssetsProvider extends AutoDisposeFutureProvider<RenderList> {
|
||||
/// See also [personAssets].
|
||||
PersonAssetsProvider(
|
||||
String personId,
|
||||
) : this._internal(
|
||||
(ref) => personAssets(
|
||||
ref as PersonAssetsRef,
|
||||
personId,
|
||||
),
|
||||
from: personAssetsProvider,
|
||||
name: r'personAssetsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$personAssetsHash,
|
||||
dependencies: PersonAssetsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PersonAssetsFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
);
|
||||
|
||||
PersonAssetsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.personId,
|
||||
}) : super.internal();
|
||||
|
||||
final String personId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<RenderList> Function(PersonAssetsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: PersonAssetsProvider._internal(
|
||||
(ref) => create(ref as PersonAssetsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
personId: personId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<RenderList> createElement() {
|
||||
return _PersonAssetsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PersonAssetsProvider && other.personId == personId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, personId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin PersonAssetsRef on AutoDisposeFutureProviderRef<RenderList> {
|
||||
/// The parameter `personId` of this provider.
|
||||
String get personId;
|
||||
}
|
||||
|
||||
class _PersonAssetsProviderElement
|
||||
extends AutoDisposeFutureProviderElement<RenderList> with PersonAssetsRef {
|
||||
_PersonAssetsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get personId => (origin as PersonAssetsProvider).personId;
|
||||
}
|
||||
|
||||
String _$updatePersonNameHash() => r'c7179a7cc558669c3b30b03fbca7782a42f2b6fd';
|
||||
|
||||
/// See also [updatePersonName].
|
||||
@ProviderFor(updatePersonName)
|
||||
const updatePersonNameProvider = UpdatePersonNameFamily();
|
||||
|
||||
/// See also [updatePersonName].
|
||||
class UpdatePersonNameFamily extends Family<AsyncValue<bool>> {
|
||||
/// See also [updatePersonName].
|
||||
const UpdatePersonNameFamily();
|
||||
|
||||
/// See also [updatePersonName].
|
||||
UpdatePersonNameProvider call(
|
||||
String personId,
|
||||
String updatedName,
|
||||
) {
|
||||
return UpdatePersonNameProvider(
|
||||
personId,
|
||||
updatedName,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
UpdatePersonNameProvider getProviderOverride(
|
||||
covariant UpdatePersonNameProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.personId,
|
||||
provider.updatedName,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'updatePersonNameProvider';
|
||||
}
|
||||
|
||||
/// See also [updatePersonName].
|
||||
class UpdatePersonNameProvider extends AutoDisposeFutureProvider<bool> {
|
||||
/// See also [updatePersonName].
|
||||
UpdatePersonNameProvider(
|
||||
String personId,
|
||||
String updatedName,
|
||||
) : this._internal(
|
||||
(ref) => updatePersonName(
|
||||
ref as UpdatePersonNameRef,
|
||||
personId,
|
||||
updatedName,
|
||||
),
|
||||
from: updatePersonNameProvider,
|
||||
name: r'updatePersonNameProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$updatePersonNameHash,
|
||||
dependencies: UpdatePersonNameFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
UpdatePersonNameFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
updatedName: updatedName,
|
||||
);
|
||||
|
||||
UpdatePersonNameProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.personId,
|
||||
required this.updatedName,
|
||||
}) : super.internal();
|
||||
|
||||
final String personId;
|
||||
final String updatedName;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<bool> Function(UpdatePersonNameRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: UpdatePersonNameProvider._internal(
|
||||
(ref) => create(ref as UpdatePersonNameRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
personId: personId,
|
||||
updatedName: updatedName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<bool> createElement() {
|
||||
return _UpdatePersonNameProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is UpdatePersonNameProvider &&
|
||||
other.personId == personId &&
|
||||
other.updatedName == updatedName;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, personId.hashCode);
|
||||
hash = _SystemHash.combine(hash, updatedName.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin UpdatePersonNameRef on AutoDisposeFutureProviderRef<bool> {
|
||||
/// The parameter `personId` of this provider.
|
||||
String get personId;
|
||||
|
||||
/// The parameter `updatedName` of this provider.
|
||||
String get updatedName;
|
||||
}
|
||||
|
||||
class _UpdatePersonNameProviderElement
|
||||
extends AutoDisposeFutureProviderElement<bool> with UpdatePersonNameRef {
|
||||
_UpdatePersonNameProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get personId => (origin as UpdatePersonNameProvider).personId;
|
||||
@override
|
||||
String get updatedName => (origin as UpdatePersonNameProvider).updatedName;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
@ -1,44 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
final personServiceProvider = Provider(
|
||||
(ref) => PersonService(
|
||||
ref.watch(apiServiceProvider),
|
||||
),
|
||||
);
|
||||
part 'person.service.g.dart';
|
||||
|
||||
@riverpod
|
||||
PersonService personService(PersonServiceRef ref) =>
|
||||
PersonService(ref.read(apiServiceProvider));
|
||||
|
||||
class PersonService {
|
||||
final Logger _log = Logger("PersonService");
|
||||
final ApiService _apiService;
|
||||
|
||||
PersonService(this._apiService);
|
||||
|
||||
Future<List<PersonResponseDto>?> getCuratedPeople() async {
|
||||
Future<List<PersonResponseDto>> getCuratedPeople() async {
|
||||
try {
|
||||
final peopleResponseDto = await _apiService.personApi.getAllPeople();
|
||||
return peopleResponseDto?.people;
|
||||
} catch (e) {
|
||||
debugPrint("Error [getCuratedPeople] ${e.toString()}");
|
||||
return null;
|
||||
return peopleResponseDto?.people ?? [];
|
||||
} catch (error, stack) {
|
||||
_log.severe("Error while fetching curated people", error, stack);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Asset>?> getPersonAssets(String id) async {
|
||||
try {
|
||||
final assets = await _apiService.personApi.getPersonAssets(id);
|
||||
|
||||
if (assets == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return assets.map((e) => Asset.remote(e)).toList();
|
||||
} catch (e) {
|
||||
debugPrint("Error [getPersonAssets] ${e.toString()}");
|
||||
return null;
|
||||
return assets?.map((e) => Asset.remote(e)).toList();
|
||||
} catch (error, stack) {
|
||||
_log.severe("Error while fetching person assets", error, stack);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<PersonResponseDto?> updateName(String id, String name) async {
|
||||
|
@ -49,9 +45,9 @@ class PersonService {
|
|||
name: name,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint("Error [updateName] ${e.toString()}");
|
||||
return null;
|
||||
} catch (error, stack) {
|
||||
_log.severe("Error while updating person name", error, stack);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
25
mobile/lib/modules/search/services/person.service.g.dart
generated
Normal file
25
mobile/lib/modules/search/services/person.service.g.dart
generated
Normal file
|
@ -0,0 +1,25 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'person.service.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$personServiceHash() => r'3fc3dcf4603c7b55c0deae65f39f6c212eea492b';
|
||||
|
||||
/// See also [personService].
|
||||
@ProviderFor(personService)
|
||||
final personServiceProvider = AutoDisposeProvider<PersonService>.internal(
|
||||
personService,
|
||||
name: r'personServiceProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$personServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef PersonServiceRef = AutoDisposeProviderRef<PersonService>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
|
||||
|
@ -64,18 +65,18 @@ class CuratedPlacesRow extends CuratedRow {
|
|||
),
|
||||
),
|
||||
),
|
||||
const Align(
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: 10),
|
||||
child: Text(
|
||||
"Your Map",
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: const Text(
|
||||
"search_page_your_map",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
).tr(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
@ -24,58 +25,55 @@ class PersonNameEditForm extends HookConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final controller = useTextEditingController(text: personName);
|
||||
final isError = useState(false);
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Add a name",
|
||||
"search_page_person_add_name_dialog_title",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
).tr(),
|
||||
content: SingleChildScrollView(
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Name',
|
||||
decoration: InputDecoration(
|
||||
hintText: 'search_page_person_add_name_dialog_hint'.tr(),
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: isError.value ? 'Error occured' : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop<PersonNameEditFormResult>(
|
||||
PersonNameEditFormResult(false, ''),
|
||||
);
|
||||
},
|
||||
onPressed: () => context.pop(
|
||||
PersonNameEditFormResult(false, ''),
|
||||
),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
"search_page_person_add_name_dialog_cancel",
|
||||
style: TextStyle(
|
||||
color: Colors.red[300],
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
).tr(),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref.read(
|
||||
updatePersonNameProvider(
|
||||
UpdatePersonName(personId, controller.text),
|
||||
),
|
||||
);
|
||||
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop<PersonNameEditFormResult>(
|
||||
PersonNameEditFormResult(true, controller.text),
|
||||
onPressed: () async {
|
||||
isError.value = false;
|
||||
final result = await ref.read(
|
||||
updatePersonNameProvider(personId, controller.text).future,
|
||||
);
|
||||
isError.value = !result;
|
||||
if (result) {
|
||||
context.pop(PersonNameEditFormResult(true, controller.text));
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
"Save",
|
||||
"search_page_person_add_name_dialog_save",
|
||||
style: TextStyle(
|
||||
color: context.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
).tr(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -2,7 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||
import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
|
||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||
|
@ -36,14 +35,7 @@ class AllPeoplePage extends HookConsumerWidget {
|
|||
),
|
||||
data: (people) => ExploreGrid(
|
||||
isPeople: true,
|
||||
curatedContent: people
|
||||
.map(
|
||||
(person) => CuratedContent(
|
||||
label: person.name,
|
||||
id: person.id,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
curatedContent: people,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||
import 'package:immich_mobile/modules/search/ui/person_name_edit_form.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart' as isar_store;
|
||||
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||
|
||||
class PersonResultPage extends HookConsumerWidget {
|
||||
|
@ -23,12 +26,12 @@ class PersonResultPage extends HookConsumerWidget {
|
|||
final name = useState(personName);
|
||||
|
||||
showEditNameDialog() {
|
||||
showDialog<PersonNameEditFormResult>(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return PersonNameEditForm(
|
||||
personId: personId,
|
||||
personName: personName,
|
||||
personName: name.value,
|
||||
);
|
||||
},
|
||||
).then((result) {
|
||||
|
@ -52,9 +55,9 @@ class PersonResultPage extends HookConsumerWidget {
|
|||
ListTile(
|
||||
leading: const Icon(Icons.edit_outlined),
|
||||
title: const Text(
|
||||
'Edit name',
|
||||
'search_page_person_edit_name',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
).tr(),
|
||||
onTap: showEditNameDialog,
|
||||
),
|
||||
],
|
||||
|
@ -65,35 +68,33 @@ class PersonResultPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
buildTitleBlock() {
|
||||
if (name.value == "") {
|
||||
return GestureDetector(
|
||||
onTap: showEditNameDialog,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Add a name',
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
color: context.themeData.colorScheme.secondary,
|
||||
),
|
||||
return GestureDetector(
|
||||
onTap: showEditNameDialog,
|
||||
child: name.value.isEmpty
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'search_page_person_add_name_title',
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
color: context.themeData.colorScheme.secondary,
|
||||
),
|
||||
).tr(),
|
||||
Text(
|
||||
'search_page_person_add_name_subtitle',
|
||||
style: context.textTheme.labelSmall,
|
||||
).tr(),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
name.value,
|
||||
style: context.textTheme.titleLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Find them fast by name with search',
|
||||
style: context.textTheme.labelSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
name.value,
|
||||
style: context.textTheme.titleLarge,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -111,41 +112,32 @@ class PersonResultPage extends HookConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
body: ref.watch(personAssetsProvider(personId)).when(
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, stackTrace) => Center(
|
||||
child: Text(
|
||||
error.toString(),
|
||||
),
|
||||
),
|
||||
data: (data) => data.isEmpty
|
||||
? const Center(
|
||||
child: Text('Opps'),
|
||||
)
|
||||
: ImmichAssetGrid(
|
||||
renderList: data,
|
||||
topWidget: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 36,
|
||||
backgroundImage: NetworkImage(
|
||||
getFaceThumbnailUrl(personId),
|
||||
headers: {
|
||||
"Authorization":
|
||||
"Bearer ${isar_store.Store.get(isar_store.StoreKey.accessToken)}",
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: buildTitleBlock(),
|
||||
),
|
||||
],
|
||||
body: ref.watch(personAssetsProvider(personId)).scaffoldBodyWhen(
|
||||
onData: (renderList) => ImmichAssetGrid(
|
||||
renderList: renderList,
|
||||
topWidget: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 36,
|
||||
backgroundImage: NetworkImage(
|
||||
getFaceThumbnailUrl(personId),
|
||||
headers: {
|
||||
"Authorization":
|
||||
"Bearer ${isar_store.Store.get(isar_store.StoreKey.accessToken)}",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: buildTitleBlock(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onError: const ScaffoldErrorBody(icon: Icons.person_off_outlined),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -77,15 +77,7 @@ class SearchPage extends HookConsumerWidget {
|
|||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
||||
error: (err, stack) => Center(child: Text('Error: $err')),
|
||||
data: (people) => CuratedPeopleRow(
|
||||
content: people
|
||||
.map(
|
||||
(person) => CuratedContent(
|
||||
id: person.id,
|
||||
label: person.name,
|
||||
),
|
||||
)
|
||||
.take(12)
|
||||
.toList(),
|
||||
content: people.take(12).toList(),
|
||||
onTap: (content, index) {
|
||||
context.autoPush(
|
||||
PersonResultRoute(
|
||||
|
@ -198,7 +190,7 @@ class SearchPage extends HookConsumerWidget {
|
|||
).tr(),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('Screenshots', style: categoryTitleStyle).tr(),
|
||||
title: Text('search_page_screenshots', style: categoryTitleStyle).tr(),
|
||||
leading: Icon(
|
||||
Icons.screenshot,
|
||||
color: categoryIconColor,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
final appSettingsServiceProvider = Provider((ref) => AppSettingsService());
|
||||
part 'app_settings.provider.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
AppSettingsService appSettingsService(AppSettingsServiceRef ref) =>
|
||||
AppSettingsService();
|
||||
|
|
26
mobile/lib/modules/settings/providers/app_settings.provider.g.dart
generated
Normal file
26
mobile/lib/modules/settings/providers/app_settings.provider.g.dart
generated
Normal file
|
@ -0,0 +1,26 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_settings.provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$appSettingsServiceHash() =>
|
||||
r'957a65af6967701112f3076b507f9738fec4b7be';
|
||||
|
||||
/// See also [appSettingsService].
|
||||
@ProviderFor(appSettingsService)
|
||||
final appSettingsServiceProvider = Provider<AppSettingsService>.internal(
|
||||
appSettingsService,
|
||||
name: r'appSettingsServiceProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$appSettingsServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef AppSettingsServiceRef = ProviderRef<AppSettingsService>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
@ -68,11 +68,10 @@ class AdvancedSettings extends HookConsumerWidget {
|
|||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: Text(
|
||||
// Not translated because the levels are only English
|
||||
"Log level: $logLevel",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
title: const Text(
|
||||
"advanced_settings_log_level_title",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
).tr(args: [logLevel]),
|
||||
subtitle: Slider(
|
||||
value: levelId.value.toDouble(),
|
||||
onChanged: (double v) => levelId.value = v.toInt(),
|
||||
|
|
|
@ -42,12 +42,12 @@ class LocalStorageSettings extends HookConsumerWidget {
|
|||
children: [
|
||||
ListTile(
|
||||
title: Text(
|
||||
"Duplicated Assets (${cacheItemCount.value})",
|
||||
"cache_settings_duplicated_assets_title",
|
||||
style: context.textTheme.labelLarge
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
).tr(),
|
||||
).tr(args: ["${cacheItemCount.value}"]),
|
||||
subtitle: const Text(
|
||||
"Photos and videos that are black listed by the app",
|
||||
"cache_settings_duplicated_assets_subtitle",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
),
|
||||
|
@ -55,7 +55,7 @@ class LocalStorageSettings extends HookConsumerWidget {
|
|||
trailing: TextButton(
|
||||
onPressed: cacheItemCount.value > 0 ? clearCache : null,
|
||||
child: Text(
|
||||
"CLEAR",
|
||||
"cache_settings_duplicated_assets_clear_button",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: cacheItemCount.value > 0 ? Colors.red : Colors.grey,
|
||||
|
|
|
@ -230,31 +230,34 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
|||
borderSide: BorderSide(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
dropdownMenuEntries: const [
|
||||
DropdownMenuEntry(value: 0, label: "Never"),
|
||||
dropdownMenuEntries: [
|
||||
DropdownMenuEntry(
|
||||
value: 0,
|
||||
label: "shared_link_edit_expire_after_option_never".tr(),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 30,
|
||||
label: '30 minutes',
|
||||
label: "shared_link_edit_expire_after_option_minutes".plural(30),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 60,
|
||||
label: '1 hour',
|
||||
label: "shared_link_edit_expire_after_option_hours".plural(1),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 60 * 6,
|
||||
label: '6 hours',
|
||||
label: "shared_link_edit_expire_after_option_hours".plural(6),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 60 * 24,
|
||||
label: '1 day',
|
||||
label: "shared_link_edit_expire_after_option_days".plural(1),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 60 * 24 * 7,
|
||||
label: '7 days',
|
||||
label: "shared_link_edit_expire_after_option_days".plural(7),
|
||||
),
|
||||
DropdownMenuEntry(
|
||||
value: 60 * 24 * 30,
|
||||
label: '30 days',
|
||||
label: "shared_link_edit_expire_after_option_days".plural(30),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -265,15 +268,15 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
|||
ClipboardData(
|
||||
text: passwordController.text.isEmpty
|
||||
? newShareLink.value
|
||||
: "Link: ${newShareLink.value}\nPassword: ${passwordController.text}",
|
||||
: "shared_link_clipboard_text".tr(
|
||||
args: [newShareLink.value, passwordController.text],
|
||||
),
|
||||
),
|
||||
).then((_) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
"Copied to clipboard",
|
||||
),
|
||||
duration: Duration(seconds: 2),
|
||||
SnackBar(
|
||||
content: const Text("shared_link_clipboard_copied_massage").tr(),
|
||||
duration: const Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -310,7 +313,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
|||
context.autoPop();
|
||||
},
|
||||
child: const Text(
|
||||
"Done",
|
||||
"share_done",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -353,7 +356,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
|||
context: context,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
toastType: ToastType.error,
|
||||
msg: 'Error while creating shared link',
|
||||
msg: 'shared_link_create_error'.tr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,43 +5,52 @@ import 'package:immich_mobile/shared/models/server_info/server_version.model.dar
|
|||
|
||||
class ServerInfo {
|
||||
final ServerVersion serverVersion;
|
||||
final ServerVersion latestVersion;
|
||||
final ServerFeatures serverFeatures;
|
||||
final ServerConfig serverConfig;
|
||||
final ServerDiskInfo serverDiskInfo;
|
||||
final bool isVersionMismatch;
|
||||
final bool isNewReleaseAvailable;
|
||||
final String versionMismatchErrorMessage;
|
||||
|
||||
ServerInfo({
|
||||
required this.serverVersion,
|
||||
required this.latestVersion,
|
||||
required this.serverFeatures,
|
||||
required this.serverConfig,
|
||||
required this.isVersionMismatch,
|
||||
required this.serverDiskInfo,
|
||||
required this.isVersionMismatch,
|
||||
required this.isNewReleaseAvailable,
|
||||
required this.versionMismatchErrorMessage,
|
||||
});
|
||||
|
||||
ServerInfo copyWith({
|
||||
ServerVersion? serverVersion,
|
||||
ServerVersion? latestVersion,
|
||||
ServerFeatures? serverFeatures,
|
||||
ServerConfig? serverConfig,
|
||||
ServerDiskInfo? serverDiskInfo,
|
||||
bool? isVersionMismatch,
|
||||
bool? isNewReleaseAvailable,
|
||||
String? versionMismatchErrorMessage,
|
||||
}) {
|
||||
return ServerInfo(
|
||||
serverVersion: serverVersion ?? this.serverVersion,
|
||||
latestVersion: latestVersion ?? this.latestVersion,
|
||||
serverFeatures: serverFeatures ?? this.serverFeatures,
|
||||
serverConfig: serverConfig ?? this.serverConfig,
|
||||
serverDiskInfo: serverDiskInfo ?? this.serverDiskInfo,
|
||||
isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch,
|
||||
isNewReleaseAvailable:
|
||||
isNewReleaseAvailable ?? this.isNewReleaseAvailable,
|
||||
versionMismatchErrorMessage:
|
||||
versionMismatchErrorMessage ?? this.versionMismatchErrorMessage,
|
||||
serverDiskInfo: serverDiskInfo ?? this.serverDiskInfo,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerInfo(serverVersion: $serverVersion, serverFeatures: $serverFeatures, serverConfig: $serverConfig, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage, serverDiskInfo: $serverDiskInfo)';
|
||||
return 'ServerInfo(serverVersion: $serverVersion, latestVersion: $latestVersion, serverFeatures: $serverFeatures, serverConfig: $serverConfig, serverDiskInfo: $serverDiskInfo, isVersionMismatch: $isVersionMismatch, isNewReleaseAvailable: $isNewReleaseAvailable, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -50,20 +59,24 @@ class ServerInfo {
|
|||
|
||||
return other is ServerInfo &&
|
||||
other.serverVersion == serverVersion &&
|
||||
other.latestVersion == latestVersion &&
|
||||
other.serverFeatures == serverFeatures &&
|
||||
other.serverConfig == serverConfig &&
|
||||
other.serverDiskInfo == serverDiskInfo &&
|
||||
other.isVersionMismatch == isVersionMismatch &&
|
||||
other.isNewReleaseAvailable == isNewReleaseAvailable &&
|
||||
other.versionMismatchErrorMessage == versionMismatchErrorMessage;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return serverVersion.hashCode ^
|
||||
latestVersion.hashCode ^
|
||||
serverFeatures.hashCode ^
|
||||
serverConfig.hashCode ^
|
||||
serverDiskInfo.hashCode ^
|
||||
isVersionMismatch.hashCode ^
|
||||
versionMismatchErrorMessage.hashCode ^
|
||||
serverDiskInfo.hashCode;
|
||||
isNewReleaseAvailable.hashCode ^
|
||||
versionMismatchErrorMessage.hashCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,7 +153,6 @@ enum StoreKey<T> {
|
|||
backupRequireWifi<bool>(6, type: bool),
|
||||
backupRequireCharging<bool>(7, type: bool),
|
||||
backupTriggerDelay<int>(8, type: int),
|
||||
githubReleaseInfo<String>(9, type: String),
|
||||
serverUrl<String>(10, type: String),
|
||||
accessToken<String>(11, type: String),
|
||||
serverEndpoint<String>(12, type: String),
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
final apiServiceProvider = Provider((ref) => ApiService());
|
||||
part 'api.provider.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
ApiService apiService(ApiServiceRef ref) => ApiService();
|
||||
|
|
24
mobile/lib/shared/providers/api.provider.g.dart
generated
Normal file
24
mobile/lib/shared/providers/api.provider.g.dart
generated
Normal file
|
@ -0,0 +1,24 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'api.provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$apiServiceHash() => r'03cbd33147a7058d56175e532ac47e1aa4858c6d';
|
||||
|
||||
/// See also [apiService].
|
||||
@ProviderFor(apiService)
|
||||
final apiServiceProvider = Provider<ApiService>.internal(
|
||||
apiService,
|
||||
name: r'apiServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$apiServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef ApiServiceRef = ProviderRef<ApiService>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
@ -11,7 +11,6 @@ import 'package:immich_mobile/modules/memories/providers/memory.provider.dart';
|
|||
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
|
||||
import 'package:immich_mobile/modules/settings/providers/notification_permission.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/release_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/tab.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
|
||||
|
@ -70,8 +69,6 @@ class AppStateNotiifer extends StateNotifier<AppStateEnum> {
|
|||
|
||||
_ref.read(websocketProvider.notifier).connect();
|
||||
|
||||
_ref.read(releaseInfoProvider.notifier).checkGithubReleaseInfo();
|
||||
|
||||
_ref
|
||||
.read(notificationPermissionProvider.notifier)
|
||||
.getNotificationPermission();
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/views/version_announcement_overlay.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class ReleaseInfoNotifier extends StateNotifier<String> {
|
||||
ReleaseInfoNotifier() : super("");
|
||||
final log = Logger('ReleaseInfoNotifier');
|
||||
void checkGithubReleaseInfo() async {
|
||||
final Client client = Client();
|
||||
|
||||
try {
|
||||
final String? localReleaseVersion =
|
||||
Store.tryGet(StoreKey.githubReleaseInfo);
|
||||
final res = await client.get(
|
||||
Uri.parse(
|
||||
"https://api.github.com/repos/immich-app/immich/releases/latest",
|
||||
),
|
||||
headers: {"Accept": "application/vnd.github.v3+json"},
|
||||
);
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
final data = jsonDecode(res.body);
|
||||
String latestTagVersion = data["tag_name"];
|
||||
state = latestTagVersion;
|
||||
|
||||
if (localReleaseVersion == null && latestTagVersion.isNotEmpty) {
|
||||
VersionAnnouncementOverlayController.appLoader.show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (latestTagVersion.isNotEmpty &&
|
||||
localReleaseVersion != latestTagVersion) {
|
||||
VersionAnnouncementOverlayController.appLoader.show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error gettting latest release version");
|
||||
|
||||
state = "";
|
||||
}
|
||||
}
|
||||
|
||||
void acknowledgeNewVersion() {
|
||||
Store.put(StoreKey.githubReleaseInfo, state);
|
||||
VersionAnnouncementOverlayController.appLoader.hide();
|
||||
}
|
||||
}
|
||||
|
||||
final releaseInfoProvider = StateNotifierProvider<ReleaseInfoNotifier, String>(
|
||||
(ref) => ReleaseInfoNotifier(),
|
||||
);
|
|
@ -18,6 +18,11 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
minor: 0,
|
||||
patch: 0,
|
||||
),
|
||||
latestVersion: const ServerVersion(
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
),
|
||||
serverFeatures: const ServerFeatures(
|
||||
map: true,
|
||||
trash: true,
|
||||
|
@ -32,6 +37,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
diskUsagePercentage: 0,
|
||||
),
|
||||
isVersionMismatch: false,
|
||||
isNewReleaseAvailable: false,
|
||||
versionMismatchErrorMessage: "",
|
||||
),
|
||||
);
|
||||
|
@ -55,6 +61,10 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
return;
|
||||
}
|
||||
|
||||
await _checkServerVersionMismatch(serverVersion);
|
||||
}
|
||||
|
||||
_checkServerVersionMismatch(ServerVersion serverVersion) async {
|
||||
state = state.copyWith(serverVersion: serverVersion);
|
||||
|
||||
var packageInfo = await PackageInfo.fromPlatform();
|
||||
|
@ -64,20 +74,32 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
if (appVersion["major"]! > serverVersion.major) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage:
|
||||
"Server is out of date. Please update to the latest major version.",
|
||||
versionMismatchErrorMessage: "profile_drawer_server_out_of_date_major".tr(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (appVersion["major"]! < serverVersion.major) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage: "profile_drawer_client_out_of_date_major".tr(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (appVersion["minor"]! > serverVersion.minor) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage:
|
||||
"Server is out of date. Consider updating to the latest minor version.",
|
||||
versionMismatchErrorMessage: "profile_drawer_server_out_of_date_minor".tr(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (appVersion["minor"]! < serverVersion.minor) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage: "profile_drawer_client_out_of_date_minor".tr(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,6 +109,25 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
);
|
||||
}
|
||||
|
||||
handleNewRelease(
|
||||
ServerVersion serverVersion,
|
||||
ServerVersion latestVersion,
|
||||
) {
|
||||
// Update local server version
|
||||
_checkServerVersionMismatch(serverVersion);
|
||||
|
||||
final majorEqual = latestVersion.major == serverVersion.major;
|
||||
final minorEqual = majorEqual && latestVersion.minor == serverVersion.minor;
|
||||
final newVersionAvailable = latestVersion.major > serverVersion.major ||
|
||||
(majorEqual && latestVersion.minor > serverVersion.minor) ||
|
||||
(minorEqual && latestVersion.patch > serverVersion.patch);
|
||||
|
||||
state = state.copyWith(
|
||||
latestVersion: latestVersion,
|
||||
isNewReleaseAvailable: newVersionAvailable,
|
||||
);
|
||||
}
|
||||
|
||||
getServerFeatures() async {
|
||||
final serverFeatures = await _serverInfoService.getServerFeatures();
|
||||
if (serverFeatures == null) {
|
||||
|
@ -120,5 +161,5 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||
|
||||
final serverInfoProvider =
|
||||
StateNotifierProvider<ServerInfoNotifier, ServerInfo>((ref) {
|
||||
return ServerInfoNotifier(ref.watch(serverInfoServiceProvider));
|
||||
return ServerInfoNotifier(ref.read(serverInfoServiceProvider));
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/models/server_info/server_version.model.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
|
@ -130,6 +131,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
|||
socket.on('on_asset_trash', _handleServerUpdates);
|
||||
socket.on('on_asset_restore', _handleServerUpdates);
|
||||
socket.on('on_asset_update', _handleServerUpdates);
|
||||
socket.on('on_new_release', _handleReleaseUpdates);
|
||||
} catch (e) {
|
||||
debugPrint("[WEBSOCKET] Catch Websocket Error - ${e.toString()}");
|
||||
}
|
||||
|
@ -204,6 +206,36 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
|||
addPendingChange(PendingAction.assetDelete, data);
|
||||
_debounce(handlePendingChanges);
|
||||
}
|
||||
|
||||
_handleReleaseUpdates(dynamic data) {
|
||||
// Json guard
|
||||
if (data is! Map) {
|
||||
return;
|
||||
}
|
||||
|
||||
final json = data.cast<String, dynamic>();
|
||||
final serverVersionJson =
|
||||
json.containsKey('serverVersion') ? json['serverVersion'] : null;
|
||||
final releaseVersionJson =
|
||||
json.containsKey('releaseVersion') ? json['releaseVersion'] : null;
|
||||
if (serverVersionJson == null || releaseVersionJson == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final serverVersionDto =
|
||||
ServerVersionResponseDto.fromJson(serverVersionJson);
|
||||
final releaseVersionDto =
|
||||
ServerVersionResponseDto.fromJson(releaseVersionJson);
|
||||
if (serverVersionDto == null || releaseVersionDto == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final serverVersion = ServerVersion.fromDto(serverVersionDto);
|
||||
final releaseVersion = ServerVersion.fromDto(releaseVersionDto);
|
||||
_ref
|
||||
.read(serverInfoProvider.notifier)
|
||||
.handleNewRelease(serverVersion, releaseVersion);
|
||||
}
|
||||
}
|
||||
|
||||
final websocketProvider =
|
||||
|
|
|
@ -785,15 +785,20 @@ class SyncService {
|
|||
bool? remote,
|
||||
int Function(Asset, Asset) compare = Asset.compareByChecksum,
|
||||
}) {
|
||||
// fast paths for trivial cases: reduces memory usage during initial sync etc.
|
||||
if (assets.isEmpty && inDb.isEmpty) {
|
||||
return const ([], [], []);
|
||||
} else if (assets.isEmpty && remote == null) {
|
||||
// remove all from database
|
||||
return (const [], const [], inDb);
|
||||
} else if (inDb.isEmpty) {
|
||||
// add all assets
|
||||
return (assets, const [], const []);
|
||||
}
|
||||
|
||||
final List<Asset> toAdd = [];
|
||||
final List<Asset> toUpdate = [];
|
||||
final List<Asset> toRemove = [];
|
||||
if (assets.isEmpty || inDb.isEmpty) {
|
||||
// fast path for trivial cases: halfes memory usage during initial sync
|
||||
return assets.isEmpty
|
||||
? (toAdd, toUpdate, inDb) // remove all from DB
|
||||
: (assets, toUpdate, toRemove); // add all assets
|
||||
}
|
||||
diffSortedListsSync(
|
||||
inDb,
|
||||
assets,
|
||||
|
|
|
@ -137,7 +137,7 @@ class AppBarServerInfo extends HookConsumerWidget {
|
|||
child: Text(
|
||||
serverInfoState.serverVersion.major > 0
|
||||
? "${serverInfoState.serverVersion.major}.${serverInfoState.serverVersion.minor}.${serverInfoState.serverVersion.patch}"
|
||||
: "?",
|
||||
: "--",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: context.textTheme.labelSmall?.color
|
||||
|
@ -207,6 +207,61 @@ class AppBarServerInfo extends HookConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Divider(
|
||||
color: Color.fromARGB(101, 201, 201, 201),
|
||||
thickness: 1,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Row(
|
||||
children: [
|
||||
if (serverInfoState.isNewReleaseAvailable)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 5.0),
|
||||
child: Icon(
|
||||
Icons.info,
|
||||
color: Color.fromARGB(255, 243, 188, 106),
|
||||
size: 12,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"server_info_box_latest_release".tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: context.textTheme.labelSmall?.color,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
child: Text(
|
||||
serverInfoState.latestVersion.major > 0
|
||||
? "${serverInfoState.latestVersion.major}.${serverInfoState.latestVersion.minor}.${serverInfoState.latestVersion.patch}"
|
||||
: "--",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: context.textTheme.labelSmall?.color
|
||||
?.withOpacity(0.5),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -50,7 +50,9 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
|
|||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
alignment: Alignment.bottomRight,
|
||||
isLabelVisible: serverInfoState.isVersionMismatch,
|
||||
isLabelVisible: serverInfoState.isVersionMismatch ||
|
||||
((user?.isAdmin ?? false) &&
|
||||
serverInfoState.isNewReleaseAvailable),
|
||||
offset: const Offset(2, 2),
|
||||
child: user == null
|
||||
? const Icon(
|
||||
|
|
33
mobile/lib/shared/ui/scaffold_error_body.dart
Normal file
33
mobile/lib/shared/ui/scaffold_error_body.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
|
||||
// Error widget to be used in Scaffold when an AsyncError is received
|
||||
class ScaffoldErrorBody extends StatelessWidget {
|
||||
final IconData icon;
|
||||
|
||||
const ScaffoldErrorBody({this.icon = Icons.error_outline, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"scaffold_body_error_occured",
|
||||
style:
|
||||
TextStyle(fontSize: 14, fontWeight: FontWeight.bold, height: 3),
|
||||
textAlign: TextAlign.center,
|
||||
).tr(),
|
||||
Center(
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 100,
|
||||
color: context.themeData.iconTheme.color?.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/providers/release_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/admin_provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class VersionAnnouncementOverlay extends HookConsumerWidget {
|
||||
const VersionAnnouncementOverlay({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bool isAdmin = ref.watch(isAdminProvider);
|
||||
|
||||
if (!isAdmin) {
|
||||
return const SizedBox.shrink(); // Don't show anything for non-admins
|
||||
}
|
||||
|
||||
void goToReleaseNote() async {
|
||||
final Uri url =
|
||||
Uri.parse('https://github.com/immich-app/immich/releases/latest');
|
||||
await launchUrl(url);
|
||||
}
|
||||
|
||||
void onAcknowledgeTapped() {
|
||||
ref.watch(releaseInfoProvider.notifier).acknowledgeNewVersion();
|
||||
}
|
||||
|
||||
return ValueListenableBuilder<bool>(
|
||||
valueListenable:
|
||||
VersionAnnouncementOverlayController.appLoader.loaderShowingNotifier,
|
||||
builder: (context, shouldShow, child) {
|
||||
if (shouldShow) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black38,
|
||||
body: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 307),
|
||||
child: Wrap(
|
||||
children: [
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(30.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"version_announcement_overlay_title",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'WorkSans',
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.indigo,
|
||||
),
|
||||
).tr(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'WorkSans',
|
||||
color: Colors.black87,
|
||||
height: 1.2,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text:
|
||||
'version_announcement_overlay_text_1'
|
||||
.tr(),
|
||||
),
|
||||
const TextSpan(
|
||||
text: ' Immich ',
|
||||
style: TextStyle(
|
||||
fontFamily: "SnowBurstOne",
|
||||
color: Colors.indigo,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
"version_announcement_overlay_text_2"
|
||||
.tr(),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
"version_announcement_overlay_release_notes"
|
||||
.tr(),
|
||||
style: const TextStyle(
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = goToReleaseNote,
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
"version_announcement_overlay_text_3"
|
||||
.tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: const StadiumBorder(),
|
||||
visualDensity: VisualDensity.standard,
|
||||
backgroundColor: Colors.indigo,
|
||||
foregroundColor: Colors.grey[50],
|
||||
elevation: 2,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 25,
|
||||
),
|
||||
),
|
||||
onPressed: onAcknowledgeTapped,
|
||||
child: const Text(
|
||||
"version_announcement_overlay_ack",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
).tr(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VersionAnnouncementOverlayController {
|
||||
static final VersionAnnouncementOverlayController appLoader =
|
||||
VersionAnnouncementOverlayController();
|
||||
ValueNotifier<bool> loaderShowingNotifier = ValueNotifier(false);
|
||||
ValueNotifier<String> loaderTextNotifier = ValueNotifier('error message');
|
||||
|
||||
void show() {
|
||||
loaderShowingNotifier.value = true;
|
||||
}
|
||||
|
||||
void hide() {
|
||||
loaderShowingNotifier.value = false;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ void handleShareAssets(
|
|||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
context.pop();
|
||||
buildContext.pop();
|
||||
},
|
||||
);
|
||||
return const ShareDialog();
|
||||
|
|
6
mobile/openapi/.openapi-generator/FILES
generated
6
mobile/openapi/.openapi-generator/FILES
generated
|
@ -66,7 +66,6 @@ doc/FileChecksumResponseDto.md
|
|||
doc/FileReportDto.md
|
||||
doc/FileReportFixDto.md
|
||||
doc/FileReportItemDto.md
|
||||
doc/ImportAssetDto.md
|
||||
doc/JobApi.md
|
||||
doc/JobCommand.md
|
||||
doc/JobCommandDto.md
|
||||
|
@ -109,7 +108,6 @@ doc/RecognitionConfig.md
|
|||
doc/ScanLibraryDto.md
|
||||
doc/SearchAlbumResponseDto.md
|
||||
doc/SearchApi.md
|
||||
doc/SearchAssetDto.md
|
||||
doc/SearchAssetResponseDto.md
|
||||
doc/SearchExploreItem.md
|
||||
doc/SearchExploreResponseDto.md
|
||||
|
@ -256,7 +254,6 @@ lib/model/file_checksum_response_dto.dart
|
|||
lib/model/file_report_dto.dart
|
||||
lib/model/file_report_fix_dto.dart
|
||||
lib/model/file_report_item_dto.dart
|
||||
lib/model/import_asset_dto.dart
|
||||
lib/model/job_command.dart
|
||||
lib/model/job_command_dto.dart
|
||||
lib/model/job_counts_dto.dart
|
||||
|
@ -293,7 +290,6 @@ lib/model/reaction_type.dart
|
|||
lib/model/recognition_config.dart
|
||||
lib/model/scan_library_dto.dart
|
||||
lib/model/search_album_response_dto.dart
|
||||
lib/model/search_asset_dto.dart
|
||||
lib/model/search_asset_response_dto.dart
|
||||
lib/model/search_explore_item.dart
|
||||
lib/model/search_explore_response_dto.dart
|
||||
|
@ -415,7 +411,6 @@ test/file_checksum_response_dto_test.dart
|
|||
test/file_report_dto_test.dart
|
||||
test/file_report_fix_dto_test.dart
|
||||
test/file_report_item_dto_test.dart
|
||||
test/import_asset_dto_test.dart
|
||||
test/job_api_test.dart
|
||||
test/job_command_dto_test.dart
|
||||
test/job_command_test.dart
|
||||
|
@ -458,7 +453,6 @@ test/recognition_config_test.dart
|
|||
test/scan_library_dto_test.dart
|
||||
test/search_album_response_dto_test.dart
|
||||
test/search_api_test.dart
|
||||
test/search_asset_dto_test.dart
|
||||
test/search_asset_response_dto_test.dart
|
||||
test/search_explore_item_test.dart
|
||||
test/search_explore_response_dto_test.dart
|
||||
|
|
6
mobile/openapi/README.md
generated
6
mobile/openapi/README.md
generated
|
@ -3,7 +3,7 @@ Immich API
|
|||
|
||||
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||
|
||||
- API version: 1.86.0
|
||||
- API version: 1.87.0
|
||||
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
||||
|
||||
## Requirements
|
||||
|
@ -111,11 +111,9 @@ Class | Method | HTTP request | Description
|
|||
*AssetApi* | [**getTimeBucket**](doc//AssetApi.md#gettimebucket) | **GET** /asset/time-bucket |
|
||||
*AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
|
||||
*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
|
||||
*AssetApi* | [**importFile**](doc//AssetApi.md#importfile) | **POST** /asset/import |
|
||||
*AssetApi* | [**restoreAssets**](doc//AssetApi.md#restoreassets) | **POST** /asset/restore |
|
||||
*AssetApi* | [**restoreTrash**](doc//AssetApi.md#restoretrash) | **POST** /asset/trash/restore |
|
||||
*AssetApi* | [**runAssetJobs**](doc//AssetApi.md#runassetjobs) | **POST** /asset/jobs |
|
||||
*AssetApi* | [**searchAsset**](doc//AssetApi.md#searchasset) | **POST** /asset/search |
|
||||
*AssetApi* | [**searchAssets**](doc//AssetApi.md#searchassets) | **GET** /assets |
|
||||
*AssetApi* | [**serveFile**](doc//AssetApi.md#servefile) | **GET** /asset/file/{id} |
|
||||
*AssetApi* | [**updateAsset**](doc//AssetApi.md#updateasset) | **PUT** /asset/{id} |
|
||||
|
@ -265,7 +263,6 @@ Class | Method | HTTP request | Description
|
|||
- [FileReportDto](doc//FileReportDto.md)
|
||||
- [FileReportFixDto](doc//FileReportFixDto.md)
|
||||
- [FileReportItemDto](doc//FileReportItemDto.md)
|
||||
- [ImportAssetDto](doc//ImportAssetDto.md)
|
||||
- [JobCommand](doc//JobCommand.md)
|
||||
- [JobCommandDto](doc//JobCommandDto.md)
|
||||
- [JobCountsDto](doc//JobCountsDto.md)
|
||||
|
@ -302,7 +299,6 @@ Class | Method | HTTP request | Description
|
|||
- [RecognitionConfig](doc//RecognitionConfig.md)
|
||||
- [ScanLibraryDto](doc//ScanLibraryDto.md)
|
||||
- [SearchAlbumResponseDto](doc//SearchAlbumResponseDto.md)
|
||||
- [SearchAssetDto](doc//SearchAssetDto.md)
|
||||
- [SearchAssetResponseDto](doc//SearchAssetResponseDto.md)
|
||||
- [SearchExploreItem](doc//SearchExploreItem.md)
|
||||
- [SearchExploreResponseDto](doc//SearchExploreResponseDto.md)
|
||||
|
|
112
mobile/openapi/doc/AssetApi.md
generated
112
mobile/openapi/doc/AssetApi.md
generated
|
@ -29,11 +29,9 @@ Method | HTTP request | Description
|
|||
[**getTimeBucket**](AssetApi.md#gettimebucket) | **GET** /asset/time-bucket |
|
||||
[**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
|
||||
[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
|
||||
[**importFile**](AssetApi.md#importfile) | **POST** /asset/import |
|
||||
[**restoreAssets**](AssetApi.md#restoreassets) | **POST** /asset/restore |
|
||||
[**restoreTrash**](AssetApi.md#restoretrash) | **POST** /asset/trash/restore |
|
||||
[**runAssetJobs**](AssetApi.md#runassetjobs) | **POST** /asset/jobs |
|
||||
[**searchAsset**](AssetApi.md#searchasset) | **POST** /asset/search |
|
||||
[**searchAssets**](AssetApi.md#searchassets) | **GET** /assets |
|
||||
[**serveFile**](AssetApi.md#servefile) | **GET** /asset/file/{id} |
|
||||
[**updateAsset**](AssetApi.md#updateasset) | **PUT** /asset/{id} |
|
||||
|
@ -1210,61 +1208,6 @@ Name | Type | Description | Notes
|
|||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **importFile**
|
||||
> AssetFileUploadResponseDto importFile(importAssetDto)
|
||||
|
||||
|
||||
|
||||
### Example
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
// TODO Configure API key authorization: cookie
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
|
||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
|
||||
// TODO Configure API key authorization: api_key
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
|
||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
|
||||
// TODO Configure HTTP Bearer authorization: bearer
|
||||
// Case 1. Use String Token
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
|
||||
// Case 2. Use Function which generate token.
|
||||
// String yourTokenGeneratorFunction() { ... }
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
||||
|
||||
final api_instance = AssetApi();
|
||||
final importAssetDto = ImportAssetDto(); // ImportAssetDto |
|
||||
|
||||
try {
|
||||
final result = api_instance.importFile(importAssetDto);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->importFile: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**importAssetDto** | [**ImportAssetDto**](ImportAssetDto.md)| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**AssetFileUploadResponseDto**](AssetFileUploadResponseDto.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **restoreAssets**
|
||||
> restoreAssets(bulkIdsDto)
|
||||
|
||||
|
@ -1423,61 +1366,6 @@ void (empty response body)
|
|||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **searchAsset**
|
||||
> List<AssetResponseDto> searchAsset(searchAssetDto)
|
||||
|
||||
|
||||
|
||||
### Example
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
// TODO Configure API key authorization: cookie
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
|
||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
|
||||
// TODO Configure API key authorization: api_key
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
|
||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
|
||||
// TODO Configure HTTP Bearer authorization: bearer
|
||||
// Case 1. Use String Token
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
|
||||
// Case 2. Use Function which generate token.
|
||||
// String yourTokenGeneratorFunction() { ... }
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
||||
|
||||
final api_instance = AssetApi();
|
||||
final searchAssetDto = SearchAssetDto(); // SearchAssetDto |
|
||||
|
||||
try {
|
||||
final result = api_instance.searchAsset(searchAssetDto);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->searchAsset: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**searchAssetDto** | [**SearchAssetDto**](SearchAssetDto.md)| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**List<AssetResponseDto>**](AssetResponseDto.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **searchAssets**
|
||||
> List<AssetResponseDto> searchAssets(id, libraryId, type, order, deviceAssetId, deviceId, checksum, isArchived, isEncoded, isExternal, isFavorite, isMotion, isOffline, isReadOnly, isVisible, withDeleted, withStacked, withExif, withPeople, createdBefore, createdAfter, updatedBefore, updatedAfter, trashedBefore, trashedAfter, takenBefore, takenAfter, originalFileName, originalPath, resizePath, webpPath, encodedVideoPath, city, state, country, make, model, lensModel, page, size)
|
||||
|
||||
|
|
28
mobile/openapi/doc/ImportAssetDto.md
generated
28
mobile/openapi/doc/ImportAssetDto.md
generated
|
@ -1,28 +0,0 @@
|
|||
# openapi.model.ImportAssetDto
|
||||
|
||||
## Load the model package
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
```
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**assetPath** | **String** | |
|
||||
**deviceAssetId** | **String** | |
|
||||
**deviceId** | **String** | |
|
||||
**duration** | **String** | | [optional]
|
||||
**fileCreatedAt** | [**DateTime**](DateTime.md) | |
|
||||
**fileModifiedAt** | [**DateTime**](DateTime.md) | |
|
||||
**isArchived** | **bool** | | [optional]
|
||||
**isExternal** | **bool** | | [optional]
|
||||
**isFavorite** | **bool** | | [optional]
|
||||
**isOffline** | **bool** | | [optional]
|
||||
**isReadOnly** | **bool** | | [optional] [default to true]
|
||||
**isVisible** | **bool** | | [optional]
|
||||
**libraryId** | **String** | | [optional]
|
||||
**sidecarPath** | **String** | | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
15
mobile/openapi/doc/SearchAssetDto.md
generated
15
mobile/openapi/doc/SearchAssetDto.md
generated
|
@ -1,15 +0,0 @@
|
|||
# openapi.model.SearchAssetDto
|
||||
|
||||
## Load the model package
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
```
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**searchTerm** | **String** | |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
2
mobile/openapi/lib/api.dart
generated
2
mobile/openapi/lib/api.dart
generated
|
@ -103,7 +103,6 @@ part 'model/file_checksum_response_dto.dart';
|
|||
part 'model/file_report_dto.dart';
|
||||
part 'model/file_report_fix_dto.dart';
|
||||
part 'model/file_report_item_dto.dart';
|
||||
part 'model/import_asset_dto.dart';
|
||||
part 'model/job_command.dart';
|
||||
part 'model/job_command_dto.dart';
|
||||
part 'model/job_counts_dto.dart';
|
||||
|
@ -140,7 +139,6 @@ part 'model/reaction_type.dart';
|
|||
part 'model/recognition_config.dart';
|
||||
part 'model/scan_library_dto.dart';
|
||||
part 'model/search_album_response_dto.dart';
|
||||
part 'model/search_asset_dto.dart';
|
||||
part 'model/search_asset_response_dto.dart';
|
||||
part 'model/search_explore_item.dart';
|
||||
part 'model/search_explore_response_dto.dart';
|
||||
|
|
97
mobile/openapi/lib/api/asset_api.dart
generated
97
mobile/openapi/lib/api/asset_api.dart
generated
|
@ -1267,53 +1267,6 @@ class AssetApi {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /asset/import' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [ImportAssetDto] importAssetDto (required):
|
||||
Future<Response> importFileWithHttpInfo(ImportAssetDto importAssetDto,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/import';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = importAssetDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [ImportAssetDto] importAssetDto (required):
|
||||
Future<AssetFileUploadResponseDto?> importFile(ImportAssetDto importAssetDto,) async {
|
||||
final response = await importFileWithHttpInfo(importAssetDto,);
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
// When a remote server returns no body with a status of 204, we shall not decode it.
|
||||
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||
// FormatException when trying to decode an empty string.
|
||||
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetFileUploadResponseDto',) as AssetFileUploadResponseDto;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /asset/restore' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
|
@ -1425,56 +1378,6 @@ class AssetApi {
|
|||
}
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /asset/search' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [SearchAssetDto] searchAssetDto (required):
|
||||
Future<Response> searchAssetWithHttpInfo(SearchAssetDto searchAssetDto,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/search';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = searchAssetDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [SearchAssetDto] searchAssetDto (required):
|
||||
Future<List<AssetResponseDto>?> searchAsset(SearchAssetDto searchAssetDto,) async {
|
||||
final response = await searchAssetWithHttpInfo(searchAssetDto,);
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
// When a remote server returns no body with a status of 204, we shall not decode it.
|
||||
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||
// FormatException when trying to decode an empty string.
|
||||
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||
final responseBody = await _decodeBodyBytes(response);
|
||||
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
|
||||
.cast<AssetResponseDto>()
|
||||
.toList();
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'GET /assets' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
|
|
4
mobile/openapi/lib/api_client.dart
generated
4
mobile/openapi/lib/api_client.dart
generated
|
@ -295,8 +295,6 @@ class ApiClient {
|
|||
return FileReportFixDto.fromJson(value);
|
||||
case 'FileReportItemDto':
|
||||
return FileReportItemDto.fromJson(value);
|
||||
case 'ImportAssetDto':
|
||||
return ImportAssetDto.fromJson(value);
|
||||
case 'JobCommand':
|
||||
return JobCommandTypeTransformer().decode(value);
|
||||
case 'JobCommandDto':
|
||||
|
@ -369,8 +367,6 @@ class ApiClient {
|
|||
return ScanLibraryDto.fromJson(value);
|
||||
case 'SearchAlbumResponseDto':
|
||||
return SearchAlbumResponseDto.fromJson(value);
|
||||
case 'SearchAssetDto':
|
||||
return SearchAssetDto.fromJson(value);
|
||||
case 'SearchAssetResponseDto':
|
||||
return SearchAssetResponseDto.fromJson(value);
|
||||
case 'SearchExploreItem':
|
||||
|
|
273
mobile/openapi/lib/model/import_asset_dto.dart
generated
273
mobile/openapi/lib/model/import_asset_dto.dart
generated
|
@ -1,273 +0,0 @@
|
|||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.12
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class ImportAssetDto {
|
||||
/// Returns a new [ImportAssetDto] instance.
|
||||
ImportAssetDto({
|
||||
required this.assetPath,
|
||||
required this.deviceAssetId,
|
||||
required this.deviceId,
|
||||
this.duration,
|
||||
required this.fileCreatedAt,
|
||||
required this.fileModifiedAt,
|
||||
this.isArchived,
|
||||
this.isExternal,
|
||||
this.isFavorite,
|
||||
this.isOffline,
|
||||
this.isReadOnly = true,
|
||||
this.isVisible,
|
||||
this.libraryId,
|
||||
this.sidecarPath,
|
||||
});
|
||||
|
||||
String assetPath;
|
||||
|
||||
String deviceAssetId;
|
||||
|
||||
String deviceId;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
String? duration;
|
||||
|
||||
DateTime fileCreatedAt;
|
||||
|
||||
DateTime fileModifiedAt;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isArchived;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isExternal;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isFavorite;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isOffline;
|
||||
|
||||
bool isReadOnly;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isVisible;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
String? libraryId;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
String? sidecarPath;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is ImportAssetDto &&
|
||||
other.assetPath == assetPath &&
|
||||
other.deviceAssetId == deviceAssetId &&
|
||||
other.deviceId == deviceId &&
|
||||
other.duration == duration &&
|
||||
other.fileCreatedAt == fileCreatedAt &&
|
||||
other.fileModifiedAt == fileModifiedAt &&
|
||||
other.isArchived == isArchived &&
|
||||
other.isExternal == isExternal &&
|
||||
other.isFavorite == isFavorite &&
|
||||
other.isOffline == isOffline &&
|
||||
other.isReadOnly == isReadOnly &&
|
||||
other.isVisible == isVisible &&
|
||||
other.libraryId == libraryId &&
|
||||
other.sidecarPath == sidecarPath;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(assetPath.hashCode) +
|
||||
(deviceAssetId.hashCode) +
|
||||
(deviceId.hashCode) +
|
||||
(duration == null ? 0 : duration!.hashCode) +
|
||||
(fileCreatedAt.hashCode) +
|
||||
(fileModifiedAt.hashCode) +
|
||||
(isArchived == null ? 0 : isArchived!.hashCode) +
|
||||
(isExternal == null ? 0 : isExternal!.hashCode) +
|
||||
(isFavorite == null ? 0 : isFavorite!.hashCode) +
|
||||
(isOffline == null ? 0 : isOffline!.hashCode) +
|
||||
(isReadOnly.hashCode) +
|
||||
(isVisible == null ? 0 : isVisible!.hashCode) +
|
||||
(libraryId == null ? 0 : libraryId!.hashCode) +
|
||||
(sidecarPath == null ? 0 : sidecarPath!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'ImportAssetDto[assetPath=$assetPath, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duration=$duration, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isVisible=$isVisible, libraryId=$libraryId, sidecarPath=$sidecarPath]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'assetPath'] = this.assetPath;
|
||||
json[r'deviceAssetId'] = this.deviceAssetId;
|
||||
json[r'deviceId'] = this.deviceId;
|
||||
if (this.duration != null) {
|
||||
json[r'duration'] = this.duration;
|
||||
} else {
|
||||
// json[r'duration'] = null;
|
||||
}
|
||||
json[r'fileCreatedAt'] = this.fileCreatedAt.toUtc().toIso8601String();
|
||||
json[r'fileModifiedAt'] = this.fileModifiedAt.toUtc().toIso8601String();
|
||||
if (this.isArchived != null) {
|
||||
json[r'isArchived'] = this.isArchived;
|
||||
} else {
|
||||
// json[r'isArchived'] = null;
|
||||
}
|
||||
if (this.isExternal != null) {
|
||||
json[r'isExternal'] = this.isExternal;
|
||||
} else {
|
||||
// json[r'isExternal'] = null;
|
||||
}
|
||||
if (this.isFavorite != null) {
|
||||
json[r'isFavorite'] = this.isFavorite;
|
||||
} else {
|
||||
// json[r'isFavorite'] = null;
|
||||
}
|
||||
if (this.isOffline != null) {
|
||||
json[r'isOffline'] = this.isOffline;
|
||||
} else {
|
||||
// json[r'isOffline'] = null;
|
||||
}
|
||||
json[r'isReadOnly'] = this.isReadOnly;
|
||||
if (this.isVisible != null) {
|
||||
json[r'isVisible'] = this.isVisible;
|
||||
} else {
|
||||
// json[r'isVisible'] = null;
|
||||
}
|
||||
if (this.libraryId != null) {
|
||||
json[r'libraryId'] = this.libraryId;
|
||||
} else {
|
||||
// json[r'libraryId'] = null;
|
||||
}
|
||||
if (this.sidecarPath != null) {
|
||||
json[r'sidecarPath'] = this.sidecarPath;
|
||||
} else {
|
||||
// json[r'sidecarPath'] = null;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [ImportAssetDto] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static ImportAssetDto? fromJson(dynamic value) {
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return ImportAssetDto(
|
||||
assetPath: mapValueOfType<String>(json, r'assetPath')!,
|
||||
deviceAssetId: mapValueOfType<String>(json, r'deviceAssetId')!,
|
||||
deviceId: mapValueOfType<String>(json, r'deviceId')!,
|
||||
duration: mapValueOfType<String>(json, r'duration'),
|
||||
fileCreatedAt: mapDateTime(json, r'fileCreatedAt', '')!,
|
||||
fileModifiedAt: mapDateTime(json, r'fileModifiedAt', '')!,
|
||||
isArchived: mapValueOfType<bool>(json, r'isArchived'),
|
||||
isExternal: mapValueOfType<bool>(json, r'isExternal'),
|
||||
isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
|
||||
isOffline: mapValueOfType<bool>(json, r'isOffline'),
|
||||
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly') ?? true,
|
||||
isVisible: mapValueOfType<bool>(json, r'isVisible'),
|
||||
libraryId: mapValueOfType<String>(json, r'libraryId'),
|
||||
sidecarPath: mapValueOfType<String>(json, r'sidecarPath'),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<ImportAssetDto> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <ImportAssetDto>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = ImportAssetDto.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, ImportAssetDto> mapFromJson(dynamic json) {
|
||||
final map = <String, ImportAssetDto>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = ImportAssetDto.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of ImportAssetDto-objects as value to a dart map
|
||||
static Map<String, List<ImportAssetDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<ImportAssetDto>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = ImportAssetDto.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'assetPath',
|
||||
'deviceAssetId',
|
||||
'deviceId',
|
||||
'fileCreatedAt',
|
||||
'fileModifiedAt',
|
||||
};
|
||||
}
|
||||
|
98
mobile/openapi/lib/model/search_asset_dto.dart
generated
98
mobile/openapi/lib/model/search_asset_dto.dart
generated
|
@ -1,98 +0,0 @@
|
|||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.12
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SearchAssetDto {
|
||||
/// Returns a new [SearchAssetDto] instance.
|
||||
SearchAssetDto({
|
||||
required this.searchTerm,
|
||||
});
|
||||
|
||||
String searchTerm;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SearchAssetDto &&
|
||||
other.searchTerm == searchTerm;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(searchTerm.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SearchAssetDto[searchTerm=$searchTerm]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'searchTerm'] = this.searchTerm;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SearchAssetDto] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SearchAssetDto? fromJson(dynamic value) {
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SearchAssetDto(
|
||||
searchTerm: mapValueOfType<String>(json, r'searchTerm')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SearchAssetDto> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SearchAssetDto>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SearchAssetDto.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SearchAssetDto> mapFromJson(dynamic json) {
|
||||
final map = <String, SearchAssetDto>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SearchAssetDto.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SearchAssetDto-objects as value to a dart map
|
||||
static Map<String, List<SearchAssetDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SearchAssetDto>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SearchAssetDto.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'searchTerm',
|
||||
};
|
||||
}
|
||||
|
10
mobile/openapi/test/asset_api_test.dart
generated
10
mobile/openapi/test/asset_api_test.dart
generated
|
@ -127,11 +127,6 @@ void main() {
|
|||
// TODO
|
||||
});
|
||||
|
||||
//Future<AssetFileUploadResponseDto> importFile(ImportAssetDto importAssetDto) async
|
||||
test('test importFile', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future restoreAssets(BulkIdsDto bulkIdsDto) async
|
||||
test('test restoreAssets', () async {
|
||||
// TODO
|
||||
|
@ -147,11 +142,6 @@ void main() {
|
|||
// TODO
|
||||
});
|
||||
|
||||
//Future<List<AssetResponseDto>> searchAsset(SearchAssetDto searchAssetDto) async
|
||||
test('test searchAsset', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<List<AssetResponseDto>> searchAssets({ String id, String libraryId, AssetTypeEnum type, AssetOrder order, String deviceAssetId, String deviceId, String checksum, bool isArchived, bool isEncoded, bool isExternal, bool isFavorite, bool isMotion, bool isOffline, bool isReadOnly, bool isVisible, bool withDeleted, bool withStacked, bool withExif, bool withPeople, DateTime createdBefore, DateTime createdAfter, DateTime updatedBefore, DateTime updatedAfter, DateTime trashedBefore, DateTime trashedAfter, DateTime takenBefore, DateTime takenAfter, String originalFileName, String originalPath, String resizePath, String webpPath, String encodedVideoPath, String city, String state, String country, String make, String model, String lensModel, num page, num size }) async
|
||||
test('test searchAssets', () async {
|
||||
// TODO
|
||||
|
|
92
mobile/openapi/test/import_asset_dto_test.dart
generated
92
mobile/openapi/test/import_asset_dto_test.dart
generated
|
@ -1,92 +0,0 @@
|
|||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.12
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// tests for ImportAssetDto
|
||||
void main() {
|
||||
// final instance = ImportAssetDto();
|
||||
|
||||
group('test ImportAssetDto', () {
|
||||
// String assetPath
|
||||
test('to test the property `assetPath`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String deviceAssetId
|
||||
test('to test the property `deviceAssetId`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String deviceId
|
||||
test('to test the property `deviceId`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String duration
|
||||
test('to test the property `duration`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// DateTime fileCreatedAt
|
||||
test('to test the property `fileCreatedAt`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// DateTime fileModifiedAt
|
||||
test('to test the property `fileModifiedAt`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isArchived
|
||||
test('to test the property `isArchived`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isExternal
|
||||
test('to test the property `isExternal`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isFavorite
|
||||
test('to test the property `isFavorite`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isOffline
|
||||
test('to test the property `isOffline`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isReadOnly (default value: true)
|
||||
test('to test the property `isReadOnly`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool isVisible
|
||||
test('to test the property `isVisible`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String libraryId
|
||||
test('to test the property `libraryId`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String sidecarPath
|
||||
test('to test the property `sidecarPath`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
27
mobile/openapi/test/search_asset_dto_test.dart
generated
27
mobile/openapi/test/search_asset_dto_test.dart
generated
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.12
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// tests for SearchAssetDto
|
||||
void main() {
|
||||
// final instance = SearchAssetDto();
|
||||
|
||||
group('test SearchAssetDto', () {
|
||||
// String searchTerm
|
||||
test('to test the property `searchTerm`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
|
@ -17,6 +17,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.0"
|
||||
analyzer_plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer_plugin
|
||||
sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.2"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -201,6 +209,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
ci:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ci
|
||||
sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -281,6 +305,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
custom_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: custom_lint
|
||||
sha256: f9a828b696930cf8307f9a3617b2b65c9b370e484dc845d69100cadb77506778
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.6"
|
||||
custom_lint_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_builder
|
||||
sha256: c6f656a4d83385fc0656ae60410ed06bb382898c45627bfb8bbaa323aea97883
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.6"
|
||||
custom_lint_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_core
|
||||
sha256: e20a67737adcf0cf2465e734dd624af535add11f9edd1f2d444909b5b0749650
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.6"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -346,7 +394,7 @@ packages:
|
|||
source: hosted
|
||||
version: "0.0.2"
|
||||
executor_lib:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: executor_lib
|
||||
sha256: "544889daa5726462657dab6410b75f2f8e3a77479d85b307a25c346e243bc38e"
|
||||
|
@ -455,10 +503,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_hooks
|
||||
sha256: "6a126f703b89499818d73305e4ce1e3de33b4ae1c5512e3b8eab4b986f46774c"
|
||||
sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.6"
|
||||
version: "0.20.3"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -540,10 +588,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: b6cb0041c6c11cefb2dcb97ef436eba43c6d41287ac6d8ca93e02a497f53a4f3
|
||||
sha256: "305203d1578f6857675f9730568548b03900ce53afd319f4aa9d2fa943334dbe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.4.5"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -578,6 +626,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.2"
|
||||
freezed_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -659,10 +715,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: hooks_riverpod
|
||||
sha256: "2bb8ae6a729e1334f71f1ef68dd5f0400dca8f01de8cbdcde062584a68017b18"
|
||||
sha256: "2827136ecc0c2abffc3a58e575db6d5b84d159977fa1edc223c97bf566aa8c73"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.8"
|
||||
version: "2.4.5"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: "94ee21a60ea2836500799f3af035dc3212b1562027f1e0031c14e087f0231449"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1175,10 +1239,42 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: b0657b5b30c81a3184bdaab353045f0a403ebd60bb381591a8b7ad77dcade793
|
||||
sha256: "2e84315036e64c59affaff7443dea51247bc2fe704461a32f26a27986fb63d55"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.4.5"
|
||||
riverpod_analyzer_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod_analyzer_utils
|
||||
sha256: d72d7096964baf288b55619fe48100001fc4564ab7923ed0a7f5c7650e03c0d6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4"
|
||||
riverpod_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: "9330309e4400f40e39a2a1d1c340e775d0fd23451cf2dd2286e03c7896fd2bd5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
riverpod_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_generator
|
||||
sha256: "5b36ad2f2b562cffb37212e8d59390b25499bf045b732276e30a207b16a25f61"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
riverpod_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_lint
|
||||
sha256: "70198738c3047ae4f6517ef1a2011a8514a980a52576c7f629a3a08810319a02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1562,7 +1658,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.0.0"
|
||||
vector_tile_renderer:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_tile_renderer
|
||||
sha256: de212da0f5e48107d3b763a940a428eb1f49d8a4664d41ac0b654f77209a2d0b
|
||||
|
|
|
@ -2,7 +2,7 @@ name: immich_mobile
|
|||
description: Immich - selfhosted backup media file on mobile phone
|
||||
|
||||
publish_to: "none"
|
||||
version: 1.86.0+110
|
||||
version: 1.87.0+111
|
||||
isar_version: &isar_version 3.1.0+1
|
||||
|
||||
environment:
|
||||
|
@ -14,8 +14,9 @@ dependencies:
|
|||
|
||||
path_provider_ios:
|
||||
photo_manager: ^2.7.2
|
||||
flutter_hooks: ^0.18.6
|
||||
hooks_riverpod: ^2.2.0
|
||||
flutter_hooks: ^0.20.3
|
||||
hooks_riverpod: ^2.4.0
|
||||
riverpod_annotation: ^2.3.0
|
||||
cached_network_image: ^3.2.2
|
||||
flutter_cache_manager: ^3.3.0
|
||||
intl: ^0.18.0
|
||||
|
@ -32,9 +33,6 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/shenlong-tanwen/flutter-vector-map-tiles.git
|
||||
ref: immich_above_4
|
||||
# Adding the following as direct dependency since flutter cannot detect them as transitive dep
|
||||
vector_tile_renderer: ^4.0.0
|
||||
executor_lib: 1.1.1
|
||||
flutter_udid: ^2.0.0
|
||||
package_info_plus: ^4.1.0
|
||||
url_launcher: ^6.1.3
|
||||
|
@ -89,6 +87,9 @@ dev_dependencies:
|
|||
mockito: ^5.3.2
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
custom_lint: ^0.5.6
|
||||
riverpod_lint: ^2.1.0
|
||||
riverpod_generator: ^2.3.3
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
# vim:sw=4:ts=4:et
|
||||
|
||||
set -e
|
||||
|
||||
entrypoint_log() {
|
||||
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
ME=$(basename $0)
|
||||
DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf"
|
||||
|
||||
# check if we have ipv6 available
|
||||
if [ ! -f "/proc/net/if_inet6" ]; then
|
||||
entrypoint_log "$ME: info: ipv6 not available"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -f "/$DEFAULT_CONF_FILE" ]; then
|
||||
entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# check if the file can be modified, e.g. not on a r/o filesystem
|
||||
touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; }
|
||||
|
||||
# check if the file is already modified, e.g. on a container restart
|
||||
grep -q "listen \[::]\:8080;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; }
|
||||
|
||||
if [ -f "/etc/os-release" ]; then
|
||||
. /etc/os-release
|
||||
else
|
||||
entrypoint_log "$ME: info: can not guess the operating system"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# enable ipv6 on default.conf listen sockets
|
||||
sed -i -E 's,listen 8080;,listen 8080;\n listen [::]:8080;,' /$DEFAULT_CONF_FILE
|
||||
|
||||
entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE"
|
||||
|
||||
exit 0
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
set -e
|
||||
|
||||
export IMMICH_WEB_URL="${IMMICH_WEB_URL:-http://immich-web:3000}"
|
||||
IMMICH_WEB_SCHEME=$(echo "$IMMICH_WEB_URL" | grep -Eo '^https?://' || echo "http://")
|
||||
export IMMICH_WEB_SCHEME
|
||||
IMMICH_WEB_HOST=$(echo "$IMMICH_WEB_URL" | cut -d '/' -f 3)
|
||||
export IMMICH_WEB_HOST
|
||||
export IMMICH_SERVER_URL="${IMMICH_SERVER_URL:-http://immich-server:3001}"
|
||||
IMMICH_SERVER_SCHEME=$(echo "$IMMICH_WEB_URL" | grep -Eo '^https?://' || echo "http://")
|
||||
export IMMICH_SERVER_SCHEME
|
||||
IMMICH_SERVER_HOST=$(echo "$IMMICH_SERVER_URL" | cut -d '/' -f 3)
|
||||
export IMMICH_SERVER_HOST
|
|
@ -1,9 +0,0 @@
|
|||
FROM ghcr.io/nginxinc/nginx-unprivileged:1.25.1-alpine3.17@sha256:c38e27fdba47f725f49177b88fdd1fd2feef11b13dc11dea3695c3feb2c6d96d
|
||||
|
||||
COPY LICENSE /licenses/LICENSE.txt
|
||||
COPY LICENSE /LICENSE
|
||||
|
||||
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
|
||||
COPY 15-set-env-variables.envsh /docker-entrypoint.d
|
||||
|
||||
COPY templates/ /etc/nginx/templates
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Hau Tran
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,72 +0,0 @@
|
|||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
map $http_x_forwarded_proto $forwarded_protocol {
|
||||
default $scheme;
|
||||
|
||||
# Only allow the values 'http' and 'https' for the X-Forwarded-Proto header.
|
||||
http http;
|
||||
https https;
|
||||
}
|
||||
|
||||
upstream server {
|
||||
server ${IMMICH_SERVER_HOST};
|
||||
keepalive 2;
|
||||
}
|
||||
|
||||
upstream web {
|
||||
server ${IMMICH_WEB_HOST};
|
||||
keepalive 2;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
|
||||
access_log off;
|
||||
client_max_body_size 50000M;
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
gzip_comp_level 2;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
gunzip on;
|
||||
|
||||
# text/html is included by default
|
||||
gzip_types
|
||||
application/javascript
|
||||
application/json
|
||||
font/ttf
|
||||
image/svg+xml
|
||||
text/css;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_buffer_size 16k;
|
||||
proxy_busy_buffers_size 24k;
|
||||
proxy_buffers 64 4k;
|
||||
proxy_force_ranges on;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $forwarded_protocol;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
location /api {
|
||||
|
||||
rewrite /api/(.*) /$1 break;
|
||||
|
||||
proxy_pass ${IMMICH_SERVER_SCHEME}server;
|
||||
}
|
||||
|
||||
location / {
|
||||
|
||||
proxy_pass ${IMMICH_WEB_SCHEME}web;
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
node_modules/
|
||||
upload/
|
||||
dist/
|
||||
coverage/
|
||||
.reverse-geocoding-dump
|
|
@ -1,33 +1,42 @@
|
|||
FROM ghcr.io/immich-app/base-server-dev:20231109 as builder
|
||||
# dev build
|
||||
FROM ghcr.io/immich-app/base-server-dev:20231109 as dev
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
WORKDIR /usr/src/app
|
||||
COPY server/package.json server/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
COPY server .
|
||||
|
||||
|
||||
FROM builder as prod
|
||||
FROM dev AS prod
|
||||
|
||||
RUN npm run build
|
||||
RUN npm prune --omit=dev --omit=optional
|
||||
|
||||
# web build
|
||||
FROM node:20.9-alpine3.18 as web
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
COPY web/package.json web/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY web .
|
||||
RUN npm run build
|
||||
|
||||
|
||||
# prod build
|
||||
FROM ghcr.io/immich-app/base-server-prod:20231109
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY --from=prod /usr/src/app/node_modules ./node_modules
|
||||
COPY --from=prod /usr/src/app/dist ./dist
|
||||
COPY --from=prod /usr/src/app/bin ./bin
|
||||
COPY ./assets ./assets
|
||||
|
||||
COPY --from=web /usr/src/app/build ./www
|
||||
COPY server/assets assets
|
||||
COPY server/package.json server/package-lock.json ./
|
||||
COPY server/start*.sh ./
|
||||
RUN npm link && npm cache clean --force
|
||||
COPY LICENSE /licenses/LICENSE.txt
|
||||
COPY LICENSE /LICENSE
|
||||
COPY package.json package-lock.json ./
|
||||
COPY start*.sh ./
|
||||
|
||||
RUN npm link && npm cache clean --force
|
||||
VOLUME /usr/src/app/upload
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
ENTRYPOINT ["tini", "--", "/bin/sh"]
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Hau Tran
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1485,48 +1485,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/asset/import": {
|
||||
"post": {
|
||||
"operationId": "importFile",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ImportAssetDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AssetFileUploadResponseDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/asset/jobs": {
|
||||
"post": {
|
||||
"operationId": "runAssetJobs",
|
||||
|
@ -1763,51 +1721,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/asset/search": {
|
||||
"post": {
|
||||
"operationId": "searchAsset",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SearchAssetDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/AssetResponseDto"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/asset/search-terms": {
|
||||
"get": {
|
||||
"operationId": "getAssetSearchTerms",
|
||||
|
@ -6139,7 +6052,7 @@
|
|||
"info": {
|
||||
"title": "Immich",
|
||||
"description": "Immich API",
|
||||
"version": "1.86.0",
|
||||
"version": "1.87.0",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
|
@ -7585,64 +7498,6 @@
|
|||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ImportAssetDto": {
|
||||
"properties": {
|
||||
"assetPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"deviceAssetId": {
|
||||
"type": "string"
|
||||
},
|
||||
"deviceId": {
|
||||
"type": "string"
|
||||
},
|
||||
"duration": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileCreatedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"fileModifiedAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"isArchived": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isExternal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isFavorite": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isOffline": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isReadOnly": {
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"isVisible": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"libraryId": {
|
||||
"format": "uuid",
|
||||
"type": "string"
|
||||
},
|
||||
"sidecarPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"assetPath",
|
||||
"deviceAssetId",
|
||||
"deviceId",
|
||||
"fileCreatedAt",
|
||||
"fileModifiedAt"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"JobCommand": {
|
||||
"enum": [
|
||||
"start",
|
||||
|
@ -8346,17 +8201,6 @@
|
|||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SearchAssetDto": {
|
||||
"properties": {
|
||||
"searchTerm": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"searchTerm"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SearchAssetResponseDto": {
|
||||
"properties": {
|
||||
"count": {
|
||||
|
|
381
server/package-lock.json
generated
381
server/package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "immich",
|
||||
"version": "1.86.0",
|
||||
"version": "1.87.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich",
|
||||
"version": "1.86.0",
|
||||
"version": "1.87.0",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.22.11",
|
||||
|
@ -64,7 +64,7 @@
|
|||
"@nestjs/testing": "^10.2.2",
|
||||
"@openapitools/openapi-generator-cli": "2.7.0",
|
||||
"@testcontainers/postgresql": "^10.2.1",
|
||||
"@types/archiver": "^5.3.2",
|
||||
"@types/archiver": "^6.0.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/cron": "^2.0.1",
|
||||
|
@ -987,9 +987,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
|
||||
"integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
|
||||
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
|
@ -1828,9 +1828,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/common": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.8.tgz",
|
||||
"integrity": "sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.9.tgz",
|
||||
"integrity": "sha512-i7vb2zMLJUDIPqjfBhMkgIITK1AnKDkFYSsM+aaRHpNa9xv/CwsiQuINaXfzStMpnwjkq5FDE3aoF0wkTfD2cQ==",
|
||||
"dependencies": {
|
||||
"iterare": "1.2.1",
|
||||
"tslib": "2.6.2",
|
||||
|
@ -1876,9 +1876,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/core": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.8.tgz",
|
||||
"integrity": "sha512-9+MZ2s8ixfY9Bl/M9ofChiyYymcwdK9ZWNH4GDMF7Am7XRAQ1oqde6MYGG05rhQwiVXuTwaYLlXciJKfsrg5qg==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.9.tgz",
|
||||
"integrity": "sha512-Hl6HC9hR7JD3YmzwcveBKeydaq9cguEsMdEghzLuVH3VEH0M+bTFHjCIKhsxMez4/O7/K6n3EhNx1Et4Z+BqWg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxtjs/opencollective": "0.3.2",
|
||||
|
@ -1937,9 +1937,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/platform-express": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.8.tgz",
|
||||
"integrity": "sha512-WoSSVtwIRc5AdGMHWVzWZK4JZLT0f4o2xW8P9gQvcX+omL8W1kXCfY8GQYXNBG84XmBNYH8r0FtC8oMe/lH5NQ==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.9.tgz",
|
||||
"integrity": "sha512-r6BSMJmLLeNgyPZJ9F8wQWCXH6rrMHMd9QbCfvyUmETci5Ofy6atiYVVXl7Ms1rAi2EEnXpVCuoydHBBqSlTbg==",
|
||||
"dependencies": {
|
||||
"body-parser": "1.20.2",
|
||||
"cors": "2.8.5",
|
||||
|
@ -1962,9 +1962,9 @@
|
|||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/@nestjs/platform-socket.io": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.8.tgz",
|
||||
"integrity": "sha512-P/Olw9alAaKD7Q1vS/ol7K81x1l7Bmi+AXthBNUPGMmG/W8kxO1krerW4rEhtF3BKJ0qJIa5bhDlb80p4lZcNA==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.9.tgz",
|
||||
"integrity": "sha512-xuXsUWUtgzdRnNBSWZADQv0sShBOsyHK7iEwwIpFMerqbthSMwjsyUv0s3hDoPEnS6Nf4MMf2KReD5JBAnMBFQ==",
|
||||
"dependencies": {
|
||||
"socket.io": "4.7.2",
|
||||
"tslib": "2.6.2"
|
||||
|
@ -2027,9 +2027,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/swagger": {
|
||||
"version": "7.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.15.tgz",
|
||||
"integrity": "sha512-ZaAO90R9MQXk4iLQLijIH6jrsllkUSYoh0Su6DECGgu8Y4Q/9LfdESwsZ9nmzr/48aLOu+wrv+cdI5Wr6fLKJw==",
|
||||
"version": "7.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.16.tgz",
|
||||
"integrity": "sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==",
|
||||
"dependencies": {
|
||||
"@nestjs/mapped-types": "2.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
|
@ -2058,9 +2058,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/testing": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.8.tgz",
|
||||
"integrity": "sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.9.tgz",
|
||||
"integrity": "sha512-E+66R27Op+WAQHHH6RnUsz7QpKApl4Bn42nheCAGvS/sxbaDJ8RKtm4stE4Iz2aioPCUvRi8j4z8Ze73k0CcGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.6.2"
|
||||
|
@ -2091,11 +2091,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@nestjs/typeorm": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.0.tgz",
|
||||
"integrity": "sha512-WQU4HCDTz4UavsFzvGUKDHqi0MO5K47yFoPXdmh+Z/hCNO7SHCMmV9jLiLukM8n5nKUqJ3jDqiljkWBcZPdCtA==",
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.1.tgz",
|
||||
"integrity": "sha512-YVFYL7D25VAVp5/G+KLXIgsRfYomA+VaFZBpm2rtwrrBOmkXNrxr7kuI2bBBO/Xy4kKBDe6wbvIVVFeEA7/ngA==",
|
||||
"dependencies": {
|
||||
"uuid": "9.0.0"
|
||||
"uuid": "9.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
||||
|
@ -2105,10 +2105,22 @@
|
|||
"typeorm": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/typeorm/node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/websockets": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.8.tgz",
|
||||
"integrity": "sha512-oZN1VJFApN7d2eftr65a36QrV0IJNGba4znqyjFnyGvtDWTDcQwzDcnEfvJBTTYhOSBNS7KDfVhne0ythkl6tg==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.9.tgz",
|
||||
"integrity": "sha512-Hp/ioNMcBtCzkubgcDHeA5KH4YLBL1jHfMEacLctKDa20Kn/LFXhJhXVWEr4jEzUKXbD+Q+GyYk1V/1rJi6eHA==",
|
||||
"dependencies": {
|
||||
"iterare": "1.2.1",
|
||||
"object-hash": "3.0.0",
|
||||
|
@ -2744,9 +2756,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/archiver": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.4.tgz",
|
||||
"integrity": "sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.1.tgz",
|
||||
"integrity": "sha512-F2+JkmDYvtQrtb2YldwL0apRB1/WB6ub+1zVF/bKp3TOygUMFqfOLuw5Fj62Q+DPwJUFz1eocMxJMu7yVpplZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/readdir-glob": "*"
|
||||
|
@ -3043,9 +3055,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||
"version": "20.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
|
||||
"integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
|
@ -3187,16 +3199,16 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz",
|
||||
"integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
|
||||
"integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/type-utils": "6.10.0",
|
||||
"@typescript-eslint/utils": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/type-utils": "6.11.0",
|
||||
"@typescript-eslint/utils": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
|
@ -3222,15 +3234,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz",
|
||||
"integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
|
||||
"integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3250,13 +3262,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz",
|
||||
"integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
|
||||
"integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0"
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
|
@ -3267,13 +3279,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz",
|
||||
"integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
|
||||
"integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/utils": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"@typescript-eslint/utils": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
|
@ -3294,9 +3306,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz",
|
||||
"integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
|
||||
"integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
|
@ -3307,13 +3319,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz",
|
||||
"integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
|
||||
"integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -3334,17 +3346,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz",
|
||||
"integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
|
||||
"integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3359,12 +3371,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz",
|
||||
"integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
|
||||
"integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3881,9 +3893,9 @@
|
|||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
|
||||
"integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
|
||||
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -4298,9 +4310,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-4.13.2.tgz",
|
||||
"integrity": "sha512-JhGfRk2ddBlZMWhQeg7vgYjfKKVsAbbEs9SWu5EMMOHIPrlJ+ZEScLDVz0Yl/N+3VP9mumCZmN7zfDzctSvquw==",
|
||||
"version": "4.14.0",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-4.14.0.tgz",
|
||||
"integrity": "sha512-2IjTzXfTkXQ+WNRy2/CVupnHJtqp6JpxacIvYbru2EvporUALnIcpiSpjJbk4V6kAbsYvrV2wRdUKllb+LfssQ==",
|
||||
"dependencies": {
|
||||
"cron-parser": "^4.6.0",
|
||||
"glob": "^8.0.3",
|
||||
|
@ -5725,15 +5737,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
|
||||
"integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
|
||||
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.3",
|
||||
"@eslint/js": "8.53.0",
|
||||
"@eslint/js": "8.54.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
|
@ -11894,9 +11906,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ts-loader": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.0.tgz",
|
||||
"integrity": "sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
|
||||
"integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
|
@ -13608,9 +13620,9 @@
|
|||
}
|
||||
},
|
||||
"@eslint/js": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
|
||||
"integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
|
||||
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@golevelup/nestjs-discovery": {
|
||||
|
@ -14236,9 +14248,9 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/common": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.8.tgz",
|
||||
"integrity": "sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.9.tgz",
|
||||
"integrity": "sha512-i7vb2zMLJUDIPqjfBhMkgIITK1AnKDkFYSsM+aaRHpNa9xv/CwsiQuINaXfzStMpnwjkq5FDE3aoF0wkTfD2cQ==",
|
||||
"requires": {
|
||||
"iterare": "1.2.1",
|
||||
"tslib": "2.6.2",
|
||||
|
@ -14264,9 +14276,9 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/core": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.8.tgz",
|
||||
"integrity": "sha512-9+MZ2s8ixfY9Bl/M9ofChiyYymcwdK9ZWNH4GDMF7Am7XRAQ1oqde6MYGG05rhQwiVXuTwaYLlXciJKfsrg5qg==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.9.tgz",
|
||||
"integrity": "sha512-Hl6HC9hR7JD3YmzwcveBKeydaq9cguEsMdEghzLuVH3VEH0M+bTFHjCIKhsxMez4/O7/K6n3EhNx1Et4Z+BqWg==",
|
||||
"requires": {
|
||||
"@nuxtjs/opencollective": "0.3.2",
|
||||
"fast-safe-stringify": "2.1.1",
|
||||
|
@ -14290,9 +14302,9 @@
|
|||
"requires": {}
|
||||
},
|
||||
"@nestjs/platform-express": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.8.tgz",
|
||||
"integrity": "sha512-WoSSVtwIRc5AdGMHWVzWZK4JZLT0f4o2xW8P9gQvcX+omL8W1kXCfY8GQYXNBG84XmBNYH8r0FtC8oMe/lH5NQ==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.9.tgz",
|
||||
"integrity": "sha512-r6BSMJmLLeNgyPZJ9F8wQWCXH6rrMHMd9QbCfvyUmETci5Ofy6atiYVVXl7Ms1rAi2EEnXpVCuoydHBBqSlTbg==",
|
||||
"requires": {
|
||||
"body-parser": "1.20.2",
|
||||
"cors": "2.8.5",
|
||||
|
@ -14309,9 +14321,9 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/platform-socket.io": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.8.tgz",
|
||||
"integrity": "sha512-P/Olw9alAaKD7Q1vS/ol7K81x1l7Bmi+AXthBNUPGMmG/W8kxO1krerW4rEhtF3BKJ0qJIa5bhDlb80p4lZcNA==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.9.tgz",
|
||||
"integrity": "sha512-xuXsUWUtgzdRnNBSWZADQv0sShBOsyHK7iEwwIpFMerqbthSMwjsyUv0s3hDoPEnS6Nf4MMf2KReD5JBAnMBFQ==",
|
||||
"requires": {
|
||||
"socket.io": "4.7.2",
|
||||
"tslib": "2.6.2"
|
||||
|
@ -14354,9 +14366,9 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/swagger": {
|
||||
"version": "7.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.15.tgz",
|
||||
"integrity": "sha512-ZaAO90R9MQXk4iLQLijIH6jrsllkUSYoh0Su6DECGgu8Y4Q/9LfdESwsZ9nmzr/48aLOu+wrv+cdI5Wr6fLKJw==",
|
||||
"version": "7.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.16.tgz",
|
||||
"integrity": "sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==",
|
||||
"requires": {
|
||||
"@nestjs/mapped-types": "2.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
|
@ -14366,9 +14378,9 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/testing": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.8.tgz",
|
||||
"integrity": "sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.9.tgz",
|
||||
"integrity": "sha512-E+66R27Op+WAQHHH6RnUsz7QpKApl4Bn42nheCAGvS/sxbaDJ8RKtm4stE4Iz2aioPCUvRi8j4z8Ze73k0CcGQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "2.6.2"
|
||||
|
@ -14383,17 +14395,24 @@
|
|||
}
|
||||
},
|
||||
"@nestjs/typeorm": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.0.tgz",
|
||||
"integrity": "sha512-WQU4HCDTz4UavsFzvGUKDHqi0MO5K47yFoPXdmh+Z/hCNO7SHCMmV9jLiLukM8n5nKUqJ3jDqiljkWBcZPdCtA==",
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.1.tgz",
|
||||
"integrity": "sha512-YVFYL7D25VAVp5/G+KLXIgsRfYomA+VaFZBpm2rtwrrBOmkXNrxr7kuI2bBBO/Xy4kKBDe6wbvIVVFeEA7/ngA==",
|
||||
"requires": {
|
||||
"uuid": "9.0.0"
|
||||
"uuid": "9.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nestjs/websockets": {
|
||||
"version": "10.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.8.tgz",
|
||||
"integrity": "sha512-oZN1VJFApN7d2eftr65a36QrV0IJNGba4znqyjFnyGvtDWTDcQwzDcnEfvJBTTYhOSBNS7KDfVhne0ythkl6tg==",
|
||||
"version": "10.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.9.tgz",
|
||||
"integrity": "sha512-Hp/ioNMcBtCzkubgcDHeA5KH4YLBL1jHfMEacLctKDa20Kn/LFXhJhXVWEr4jEzUKXbD+Q+GyYk1V/1rJi6eHA==",
|
||||
"requires": {
|
||||
"iterare": "1.2.1",
|
||||
"object-hash": "3.0.0",
|
||||
|
@ -14872,9 +14891,9 @@
|
|||
}
|
||||
},
|
||||
"@types/archiver": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.4.tgz",
|
||||
"integrity": "sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.1.tgz",
|
||||
"integrity": "sha512-F2+JkmDYvtQrtb2YldwL0apRB1/WB6ub+1zVF/bKp3TOygUMFqfOLuw5Fj62Q+DPwJUFz1eocMxJMu7yVpplZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/readdir-glob": "*"
|
||||
|
@ -15170,9 +15189,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||
"version": "20.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
|
||||
"integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
|
||||
"requires": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
|
@ -15314,16 +15333,16 @@
|
|||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz",
|
||||
"integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
|
||||
"integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/type-utils": "6.10.0",
|
||||
"@typescript-eslint/utils": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/type-utils": "6.11.0",
|
||||
"@typescript-eslint/utils": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
|
@ -15333,54 +15352,54 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz",
|
||||
"integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
|
||||
"integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz",
|
||||
"integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
|
||||
"integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0"
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz",
|
||||
"integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
|
||||
"integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/utils": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"@typescript-eslint/utils": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz",
|
||||
"integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
|
||||
"integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz",
|
||||
"integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
|
||||
"integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/visitor-keys": "6.11.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -15389,27 +15408,27 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz",
|
||||
"integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
|
||||
"integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "6.10.0",
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||
"@typescript-eslint/scope-manager": "6.11.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"@typescript-eslint/typescript-estree": "6.11.0",
|
||||
"semver": "^7.5.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz",
|
||||
"integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==",
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
|
||||
"integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "6.10.0",
|
||||
"@typescript-eslint/types": "6.11.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
}
|
||||
},
|
||||
|
@ -15841,9 +15860,9 @@
|
|||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
|
||||
"integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
|
||||
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -16143,9 +16162,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"bullmq": {
|
||||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-4.13.2.tgz",
|
||||
"integrity": "sha512-JhGfRk2ddBlZMWhQeg7vgYjfKKVsAbbEs9SWu5EMMOHIPrlJ+ZEScLDVz0Yl/N+3VP9mumCZmN7zfDzctSvquw==",
|
||||
"version": "4.14.0",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-4.14.0.tgz",
|
||||
"integrity": "sha512-2IjTzXfTkXQ+WNRy2/CVupnHJtqp6JpxacIvYbru2EvporUALnIcpiSpjJbk4V6kAbsYvrV2wRdUKllb+LfssQ==",
|
||||
"requires": {
|
||||
"cron-parser": "^4.6.0",
|
||||
"glob": "^8.0.3",
|
||||
|
@ -17172,15 +17191,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
|
||||
"integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
|
||||
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.3",
|
||||
"@eslint/js": "8.53.0",
|
||||
"@eslint/js": "8.54.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
|
@ -21766,9 +21785,9 @@
|
|||
}
|
||||
},
|
||||
"ts-loader": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.0.tgz",
|
||||
"integrity": "sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
|
||||
"integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "immich",
|
||||
"version": "1.86.0",
|
||||
"version": "1.87.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
@ -90,7 +90,7 @@
|
|||
"@nestjs/testing": "^10.2.2",
|
||||
"@openapitools/openapi-generator-cli": "2.7.0",
|
||||
"@testcontainers/postgresql": "^10.2.1",
|
||||
"@types/archiver": "^5.3.2",
|
||||
"@types/archiver": "^6.0.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/cron": "^2.0.1",
|
||||
|
|
|
@ -15,7 +15,7 @@ export class EnablePasswordLoginCommand extends CommandRunner {
|
|||
const config = await this.configService.getConfig();
|
||||
config.passwordLogin.enabled = true;
|
||||
await this.configService.updateConfig(config);
|
||||
await axios.post('http://localhost:3001/refresh-config');
|
||||
await axios.post('http://localhost:3001/api/refresh-config');
|
||||
console.log('Password login has been enabled.');
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export class DisablePasswordLoginCommand extends CommandRunner {
|
|||
const config = await this.configService.getConfig();
|
||||
config.passwordLogin.enabled = false;
|
||||
await this.configService.updateConfig(config);
|
||||
await axios.post('http://localhost:3001/refresh-config');
|
||||
await axios.post('http://localhost:3001/api/refresh-config');
|
||||
console.log('Password login has been disabled.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,9 +306,9 @@ describe(SystemConfigService.name, () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getTheme', () => {
|
||||
describe('getCustomCss', () => {
|
||||
it('should return the default theme', async () => {
|
||||
await expect(sut.getTheme()).resolves.toEqual(defaults.theme);
|
||||
await expect(sut.getCustomCss()).resolves.toEqual(defaults.theme.customCss);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue