feat(server): lighter buckets ()

* feat(web): lighter timeline buckets

* GalleryViewer

* weird ssr

* Remove generics from AssetInteraction

* ensure keys on getAssetInfo, alt-text

* empty - trigger ci

* re-add alt-text

* test fix

* update tests

* tests

* missing import

* feat(server): lighter buckets

* fix: flappy e2e test

* lint

* revert settings

* unneeded cast

* fix after merge

* Adapt web client to consume new server response format

* test

* missing import

* lint

* Use nulls, make-sql

* openapi battle

* date->string

* tests

* tests

* lint/tests

* lint

* test

* push aggregation to query

* openapi

* stack as tuple

* openapi

* update references to description

* update alt text tests

* update sql

* update sql

* update timeline tests

* linting, fix expected response

* string tuple

* fix spec

* fix

* silly generator

* rename patch

* minimize sorting

* review

* lint

* lint

* sql

* test

* avoid abbreviations

* review comment - type safety in test

* merge conflicts

* lint

* lint/abbreviations

* remove unncessary code

* review comments

* sql

* re-add package-lock

* use booleans, fix visibility in openapi spec, less cursed controller

* update sql

* no need to use sql template

* array access actually doesn't seem to matter

* remove redundant code

* re-add sql decorator

* unused type

* remove null assertions

* bad merge

* Fix test

* shave

* extra clean shave

* use decorator for content type

* redundant types

* redundant comment

* update comment

* unnecessary res

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Min Idzelis 2025-05-19 17:40:48 -04:00 committed by GitHub
parent 59f666b115
commit e7edbcdf04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 1109 additions and 510 deletions

View file

@ -1,5 +1,5 @@
#!/usr/bin/env bash
OPENAPI_GENERATOR_VERSION=v7.8.0
OPENAPI_GENERATOR_VERSION=v7.12.0
# usage: ./bin/generate-open-api.sh
@ -8,6 +8,7 @@ function dart {
cd ./templates/mobile/serialization/native
wget -O native_class.mustache https://raw.githubusercontent.com/OpenAPITools/openapi-generator/$OPENAPI_GENERATOR_VERSION/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache
patch --no-backup-if-mismatch -u native_class.mustache <native_class.mustache.patch
patch --no-backup-if-mismatch -u native_class.mustache <native_class_nullable_items_in_arrays.patch
cd ../../
wget -O api.mustache https://raw.githubusercontent.com/OpenAPITools/openapi-generator/$OPENAPI_GENERATOR_VERSION/modules/openapi-generator/src/main/resources/dart2/api.mustache

View file

@ -7284,6 +7284,24 @@
"$ref": "#/components/schemas/AssetOrder"
}
},
{
"name": "page",
"required": false,
"in": "query",
"schema": {
"minimum": 1,
"type": "number"
}
},
{
"name": "pageSize",
"required": false,
"in": "query",
"schema": {
"minimum": 1,
"type": "number"
}
},
{
"name": "personId",
"required": false,
@ -7293,14 +7311,6 @@
"type": "string"
}
},
{
"name": "size",
"required": true,
"in": "query",
"schema": {
"$ref": "#/components/schemas/TimeBucketSize"
}
},
{
"name": "tagId",
"required": false,
@ -7357,10 +7367,7 @@
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/AssetResponseDto"
},
"type": "array"
"$ref": "#/components/schemas/TimeBucketAssetResponseDto"
}
}
},
@ -7437,14 +7444,6 @@
"type": "string"
}
},
{
"name": "size",
"required": true,
"in": "query",
"schema": {
"$ref": "#/components/schemas/TimeBucketSize"
}
},
{
"name": "tagId",
"required": false,
@ -7494,7 +7493,7 @@
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/TimeBucketResponseDto"
"$ref": "#/components/schemas/TimeBucketsResponseDto"
},
"type": "array"
}
@ -14069,7 +14068,131 @@
],
"type": "object"
},
"TimeBucketResponseDto": {
"TimeBucketAssetResponseDto": {
"properties": {
"city": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"country": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"duration": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"id": {
"items": {
"type": "string"
},
"type": "array"
},
"isFavorite": {
"items": {
"type": "boolean"
},
"type": "array"
},
"isImage": {
"items": {
"type": "boolean"
},
"type": "array"
},
"isTrashed": {
"items": {
"type": "boolean"
},
"type": "array"
},
"livePhotoVideoId": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"localDateTime": {
"items": {
"type": "string"
},
"type": "array"
},
"ownerId": {
"items": {
"type": "string"
},
"type": "array"
},
"projectionType": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"ratio": {
"items": {
"type": "number"
},
"type": "array"
},
"stack": {
"description": "(stack ID, stack asset count) tuple",
"items": {
"items": {
"type": "string"
},
"maxItems": 2,
"minItems": 2,
"nullable": true,
"type": "array"
},
"type": "array"
},
"thumbhash": {
"items": {
"nullable": true,
"type": "string"
},
"type": "array"
},
"visibility": {
"items": {
"$ref": "#/components/schemas/AssetVisibility"
},
"type": "array"
}
},
"required": [
"city",
"country",
"duration",
"id",
"isFavorite",
"isImage",
"isTrashed",
"livePhotoVideoId",
"localDateTime",
"ownerId",
"projectionType",
"ratio",
"thumbhash",
"visibility"
],
"type": "object"
},
"TimeBucketsResponseDto": {
"properties": {
"count": {
"type": "integer"
@ -14084,13 +14207,6 @@
],
"type": "object"
},
"TimeBucketSize": {
"enum": [
"DAY",
"MONTH"
],
"type": "string"
},
"ToneMapping": {
"enum": [
"hable",

View file

@ -32,7 +32,7 @@ class {{{classname}}} {
{{/required}}
{{/isNullable}}
{{/isEnum}}
{{{datatypeWithEnum}}}{{#isNullable}}?{{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isNullable}} {{{name}}};
{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}<{{{items.dataType}}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isArray}}{{{datatypeWithEnum}}}{{/isArray}}{{#isNullable}}?{{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isNullable}} {{{name}}};
{{/vars}}
@override

View file

@ -0,0 +1,13 @@
diff --git a/open-api/templates/mobile/serialization/native/native_class.mustache b/open-api/templates/mobile/serialization/native/native_class.mustache
index 9a7b1439b..9f40d5b0b 100644
--- a/open-api/templates/mobile/serialization/native/native_class.mustache
+++ b/open-api/templates/mobile/serialization/native/native_class.mustache
@@ -32,7 +32,7 @@ class {{{classname}}} {
{{/required}}
{{/isNullable}}
{{/isEnum}}
- {{{datatypeWithEnum}}}{{#isNullable}}?{{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isNullable}} {{{name}}};
+ {{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}<{{{items.dataType}}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isArray}}{{{datatypeWithEnum}}}{{/isArray}}{{#isNullable}}?{{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isNullable}} {{{name}}};
{{/vars}}
@override

View file

@ -1420,7 +1420,25 @@ export type TagBulkAssetsResponseDto = {
export type TagUpdateDto = {
color?: string | null;
};
export type TimeBucketResponseDto = {
export type TimeBucketAssetResponseDto = {
city: (string | null)[];
country: (string | null)[];
duration: (string | null)[];
id: string[];
isFavorite: boolean[];
isImage: boolean[];
isTrashed: boolean[];
livePhotoVideoId: (string | null)[];
localDateTime: string[];
ownerId: string[];
projectionType: (string | null)[];
ratio: number[];
/** (stack ID, stack asset count) tuple */
stack?: (string[] | null)[];
thumbhash: (string | null)[];
visibility: AssetVisibility[];
};
export type TimeBucketsResponseDto = {
count: number;
timeBucket: string;
};
@ -3367,14 +3385,15 @@ export function tagAssets({ id, bulkIdsDto }: {
body: bulkIdsDto
})));
}
export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, personId, size, tagId, timeBucket, userId, visibility, withPartners, withStacked }: {
export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, page, pageSize, personId, tagId, timeBucket, userId, visibility, withPartners, withStacked }: {
albumId?: string;
isFavorite?: boolean;
isTrashed?: boolean;
key?: string;
order?: AssetOrder;
page?: number;
pageSize?: number;
personId?: string;
size: TimeBucketSize;
tagId?: string;
timeBucket: string;
userId?: string;
@ -3384,15 +3403,16 @@ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, pers
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetResponseDto[];
data: TimeBucketAssetResponseDto;
}>(`/timeline/bucket${QS.query(QS.explode({
albumId,
isFavorite,
isTrashed,
key,
order,
page,
pageSize,
personId,
size,
tagId,
timeBucket,
userId,
@ -3403,14 +3423,13 @@ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, pers
...opts
}));
}
export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, personId, size, tagId, userId, visibility, withPartners, withStacked }: {
export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, personId, tagId, userId, visibility, withPartners, withStacked }: {
albumId?: string;
isFavorite?: boolean;
isTrashed?: boolean;
key?: string;
order?: AssetOrder;
personId?: string;
size: TimeBucketSize;
tagId?: string;
userId?: string;
visibility?: AssetVisibility;
@ -3419,7 +3438,7 @@ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, per
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: TimeBucketResponseDto[];
data: TimeBucketsResponseDto[];
}>(`/timeline/buckets${QS.query(QS.explode({
albumId,
isFavorite,
@ -3427,7 +3446,6 @@ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, per
key,
order,
personId,
size,
tagId,
userId,
visibility,
@ -3921,7 +3939,3 @@ export enum OAuthTokenEndpointAuthMethod {
ClientSecretPost = "client_secret_post",
ClientSecretBasic = "client_secret_basic"
}
export enum TimeBucketSize {
Day = "DAY",
Month = "MONTH"
}