From b4ad1c4f882b28e11e993b74ae341154e8e23a37 Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Tue, 1 Feb 2022 22:02:08 +0100 Subject: [PATCH 1/3] Add blurhash generation --- api/go.mod | 1 + api/go.sum | 2 + api/graphql/models/media.go | 16 +++++ api/scanner/queue.go | 23 ++++++-- api/scanner/thumbnail_blurhash.go | 98 +++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 api/scanner/thumbnail_blurhash.go diff --git a/api/go.mod b/api/go.mod index cde3c2c..0a02010 100644 --- a/api/go.mod +++ b/api/go.mod @@ -7,6 +7,7 @@ require ( github.com/Kagami/go-face v0.0.0-20210630145111-0c14797b4d0e github.com/agnivade/levenshtein v1.1.1 // indirect github.com/barasher/go-exiftool v1.7.0 + github.com/buckket/go-blurhash v1.1.0 // indirect github.com/disintegration/imaging v1.6.2 github.com/felixge/httpsnoop v1.0.2 // indirect github.com/go-sql-driver/mysql v1.6.0 diff --git a/api/go.sum b/api/go.sum index 7cf51d9..e095497 100644 --- a/api/go.sum +++ b/api/go.sum @@ -15,6 +15,8 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/barasher/go-exiftool v1.7.0 h1:EOGb5D6TpWXmqsnEjJ0ai6+tIW2gZFwIoS9O/33Nixs= github.com/barasher/go-exiftool v1.7.0/go.mod h1:F9s/a3uHSM8YniVfwF+sbQUtP8Gmh9nyzigNF+8vsWo= +github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do= +github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= diff --git a/api/graphql/models/media.go b/api/graphql/models/media.go index 6ed4485..3a7e1cb 100644 --- a/api/graphql/models/media.go +++ b/api/graphql/models/media.go @@ -29,6 +29,7 @@ type Media struct { SideCarPath *string SideCarHash *string `gorm:"unique"` Faces []*ImageFace `gorm:"constraint:OnDelete:CASCADE;"` + Blurhash *string `gorm:""` // Only used internally CounterpartPath *string `gorm:"-"` @@ -49,6 +50,21 @@ func (m *Media) Date() time.Time { return m.DateShot } +func (m *Media) Thumbnail() (*MediaURL, error) { + if len(m.MediaURL) == 0 { + return nil, errors.New("media.MediaURL is empty") + } + + for _, url := range m.MediaURL { + if url.Purpose == PhotoThumbnail || url.Purpose == VideoThumbnail { + url.Media = m + return &url, nil + } + } + + return nil, nil +} + type MediaType string const ( diff --git a/api/scanner/queue.go b/api/scanner/queue.go index 42d5304..1037f8c 100644 --- a/api/scanner/queue.go +++ b/api/scanner/queue.go @@ -9,6 +9,7 @@ import ( "github.com/photoview/photoview/api/graphql/models" "github.com/photoview/photoview/api/graphql/notification" "github.com/photoview/photoview/api/scanner/scanner_cache" + "github.com/photoview/photoview/api/scanner/scanner_utils" "github.com/photoview/photoview/api/utils" "github.com/pkg/errors" "gorm.io/gorm" @@ -156,8 +157,20 @@ func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { notification.BroadcastNotification(&models.Notification{ Key: "global-scanner-progress", Type: models.NotificationTypeMessage, - Header: fmt.Sprintf("Scanner complete"), - Content: fmt.Sprintf("All jobs have been scanned"), + Header: "Generating blurhashes", + Content: "Generating blurhashes for newly scanned media", + Positive: true, + }) + + if err := GenerateBlurhashes(queue.db); err != nil { + scanner_utils.ScannerError("Failed to generate blurhashes: %v", err) + } + + notification.BroadcastNotification(&models.Notification{ + Key: "global-scanner-progress", + Type: models.NotificationTypeMessage, + Header: "Scanner complete", + Content: "All jobs have been scanned", Positive: true, }) } else { @@ -165,7 +178,7 @@ func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { notification.BroadcastNotification(&models.Notification{ Key: "global-scanner-progress", Type: models.NotificationTypeMessage, - Header: fmt.Sprintf("Scanning media"), + Header: "Scanning media", Content: fmt.Sprintf("%d jobs in progress\n%d jobs waiting", in_progress_length, up_next_length), }) }) @@ -191,7 +204,9 @@ func AddAllToQueue() error { } for _, user := range users { - AddUserToQueue(user) + if err := AddUserToQueue(user); err != nil { + return errors.Wrapf(err, "failed to add user for scanning (%d)", user.ID) + } } return nil diff --git a/api/scanner/thumbnail_blurhash.go b/api/scanner/thumbnail_blurhash.go new file mode 100644 index 0000000..066ad82 --- /dev/null +++ b/api/scanner/thumbnail_blurhash.go @@ -0,0 +1,98 @@ +package scanner + +import ( + "fmt" + "image" + "log" + "os" + + "github.com/buckket/go-blurhash" + "github.com/photoview/photoview/api/graphql/models" + "gorm.io/gorm" +) + +// GenerateBlurhashes queries the database for media that are missing a blurhash and computes one for them. +// This function blocks until all hashes have been computed +func GenerateBlurhashes(db *gorm.DB) error { + var results []*models.Media + + processErrors := make([]error, 0) + + query := db.Model(&models.Media{}). + Preload("MediaURL"). + Joins("INNER JOIN media_urls ON media.id = media_urls.media_id"). + Where("blurhash IS NULL"). + Where("media_urls.purpose = 'thumbnail' OR media_urls.purpose = 'video-thumbnail'") + + err := query.FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error { + log.Printf("generating %d blurhashes", len(results)) + + hashes := make([]*string, len(results)) + + for i, row := range results { + + thumbnail, err := row.Thumbnail() + if err != nil { + log.Printf("failed to get thumbnail for media to generate blurhash (%d): %v", row.ID, err) + processErrors = append(processErrors, err) + continue + } + + hashStr, err := GenerateBlurhashFromThumbnail(thumbnail) + if err != nil { + log.Printf("failed to generate blurhash for media (%d): %v", row.ID, err) + processErrors = append(processErrors, err) + continue + } + + hashes[i] = &hashStr + results[i].Blurhash = &hashStr + } + + tx.Save(results) + // if err := db.Update("blurhash", hashes).Error; err != nil { + // return err + // } + + return nil + }).Error + + if err != nil { + return err + } + + if len(processErrors) == 0 { + return nil + } else { + return fmt.Errorf("failed to generate %d blurhashes", len(processErrors)) + } +} + +// GenerateBlurhashFromThumbnail generates a blurhash for a single media and stores it in the database +func GenerateBlurhashFromThumbnail(thumbnail *models.MediaURL) (string, error) { + thumbnail_path, err := thumbnail.CachedPath() + if err != nil { + return "", err + } + + imageFile, err := os.Open(thumbnail_path) + if err != nil { + return "", err + } + + imageData, _, err := image.Decode(imageFile) + if err != nil { + return "", err + } + + hashStr, err := blurhash.Encode(4, 3, imageData) + if err != nil { + return "", err + } + + // if err := db.Model(&models.Media{}).Where("id = ?", thumbnail.MediaID).Update("blurhash", hashStr).Error; err != nil { + // return "", err + // } + + return hashStr, nil +} From 0d9760b33f884d76740b4eeb927cdefcbd26421a Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Tue, 1 Feb 2022 23:39:19 +0100 Subject: [PATCH 2/3] Integrate blurhashes with UI --- api/go.mod | 2 +- api/graphql/generated.go | 1750 ++++++++++++++--- api/graphql/models/media.go | 2 +- api/graphql/schema.graphql | 2 + api/scanner/thumbnail_blurhash.go | 4 +- ui/package-lock.json | 446 +++-- ui/package.json | 5 + ui/src/Pages/AlbumPage/AlbumPage.tsx | 1 + .../AlbumPage/__generated__/albumQuery.ts | 78 +- .../SingleFaceGroup/SingleFaceGroup.tsx | 1 + .../__generated__/singleFaceGroup.ts | 66 +- ui/src/Pages/PlacesPage/MapPresentMarker.tsx | 1 + .../__generated__/placePageMapboxToken.ts | 4 +- .../__generated__/placePageQueryMedia.ts | 48 +- ui/src/Pages/SharePage/AlbumSharePage.tsx | 1 + .../__generated__/shareAlbumQuery.ts | 143 +- ui/src/__generated__/adminQuery.ts | 6 +- ui/src/__generated__/mapboxEnabledQuery.ts | 2 +- .../components/albumGallery/AlbumGallery.tsx | 1 + .../photoGallery/MediaThumbnail.tsx | 4 +- .../photoGallery/PhotoGallery.test.tsx | 4 + .../components/photoGallery/PhotoGallery.tsx | 1 + .../photoGallery/ProtectedMedia.tsx | 62 +- .../photoGallery/photoGalleryReducer.test.ts | 3 + .../timelineGallery/TimelineGallery.test.tsx | 2 - .../timelineGallery/TimelineGallery.tsx | 1 + .../__generated__/myTimeline.ts | 4 + .../timelineGallery/timelineTestData.ts | 5 + 28 files changed, 2002 insertions(+), 647 deletions(-) diff --git a/api/go.mod b/api/go.mod index 0a02010..d10f011 100644 --- a/api/go.mod +++ b/api/go.mod @@ -7,7 +7,7 @@ require ( github.com/Kagami/go-face v0.0.0-20210630145111-0c14797b4d0e github.com/agnivade/levenshtein v1.1.1 // indirect github.com/barasher/go-exiftool v1.7.0 - github.com/buckket/go-blurhash v1.1.0 // indirect + github.com/buckket/go-blurhash v1.1.0 github.com/disintegration/imaging v1.6.2 github.com/felixge/httpsnoop v1.0.2 // indirect github.com/go-sql-driver/mysql v1.6.0 diff --git a/api/graphql/generated.go b/api/graphql/generated.go index 8b3ed2a..29e3972 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -103,6 +103,7 @@ type ComplexityRoot struct { Media struct { Album func(childComplexity int) int + Blurhash func(childComplexity int) int Date func(childComplexity int) int Downloads func(childComplexity int) int Exif func(childComplexity int) int @@ -124,7 +125,7 @@ type ComplexityRoot struct { Title func(childComplexity int) int } - MediaExif struct { + MediaEXIF struct { Aperture func(childComplexity int) int Camera func(childComplexity int) int Coordinates func(childComplexity int) int @@ -591,6 +592,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Media.Album(childComplexity), true + case "Media.blurhash": + if e.complexity.Media.Blurhash == nil { + break + } + + return e.complexity.Media.Blurhash(childComplexity), true + case "Media.date": if e.complexity.Media.Date == nil { break @@ -704,95 +712,95 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.MediaDownload.Title(childComplexity), true case "MediaEXIF.aperture": - if e.complexity.MediaExif.Aperture == nil { + if e.complexity.MediaEXIF.Aperture == nil { break } - return e.complexity.MediaExif.Aperture(childComplexity), true + return e.complexity.MediaEXIF.Aperture(childComplexity), true case "MediaEXIF.camera": - if e.complexity.MediaExif.Camera == nil { + if e.complexity.MediaEXIF.Camera == nil { break } - return e.complexity.MediaExif.Camera(childComplexity), true + return e.complexity.MediaEXIF.Camera(childComplexity), true case "MediaEXIF.coordinates": - if e.complexity.MediaExif.Coordinates == nil { + if e.complexity.MediaEXIF.Coordinates == nil { break } - return e.complexity.MediaExif.Coordinates(childComplexity), true + return e.complexity.MediaEXIF.Coordinates(childComplexity), true case "MediaEXIF.dateShot": - if e.complexity.MediaExif.DateShot == nil { + if e.complexity.MediaEXIF.DateShot == nil { break } - return e.complexity.MediaExif.DateShot(childComplexity), true + return e.complexity.MediaEXIF.DateShot(childComplexity), true case "MediaEXIF.exposure": - if e.complexity.MediaExif.Exposure == nil { + if e.complexity.MediaEXIF.Exposure == nil { break } - return e.complexity.MediaExif.Exposure(childComplexity), true + return e.complexity.MediaEXIF.Exposure(childComplexity), true case "MediaEXIF.exposureProgram": - if e.complexity.MediaExif.ExposureProgram == nil { + if e.complexity.MediaEXIF.ExposureProgram == nil { break } - return e.complexity.MediaExif.ExposureProgram(childComplexity), true + return e.complexity.MediaEXIF.ExposureProgram(childComplexity), true case "MediaEXIF.flash": - if e.complexity.MediaExif.Flash == nil { + if e.complexity.MediaEXIF.Flash == nil { break } - return e.complexity.MediaExif.Flash(childComplexity), true + return e.complexity.MediaEXIF.Flash(childComplexity), true case "MediaEXIF.focalLength": - if e.complexity.MediaExif.FocalLength == nil { + if e.complexity.MediaEXIF.FocalLength == nil { break } - return e.complexity.MediaExif.FocalLength(childComplexity), true + return e.complexity.MediaEXIF.FocalLength(childComplexity), true case "MediaEXIF.id": - if e.complexity.MediaExif.ID == nil { + if e.complexity.MediaEXIF.ID == nil { break } - return e.complexity.MediaExif.ID(childComplexity), true + return e.complexity.MediaEXIF.ID(childComplexity), true case "MediaEXIF.iso": - if e.complexity.MediaExif.Iso == nil { + if e.complexity.MediaEXIF.Iso == nil { break } - return e.complexity.MediaExif.Iso(childComplexity), true + return e.complexity.MediaEXIF.Iso(childComplexity), true case "MediaEXIF.lens": - if e.complexity.MediaExif.Lens == nil { + if e.complexity.MediaEXIF.Lens == nil { break } - return e.complexity.MediaExif.Lens(childComplexity), true + return e.complexity.MediaEXIF.Lens(childComplexity), true case "MediaEXIF.maker": - if e.complexity.MediaExif.Maker == nil { + if e.complexity.MediaEXIF.Maker == nil { break } - return e.complexity.MediaExif.Maker(childComplexity), true + return e.complexity.MediaEXIF.Maker(childComplexity), true case "MediaEXIF.media": - if e.complexity.MediaExif.Media == nil { + if e.complexity.MediaEXIF.Media == nil { break } - return e.complexity.MediaExif.Media(childComplexity), true + return e.complexity.MediaEXIF.Media(childComplexity), true case "MediaURL.fileSize": if e.complexity.MediaURL.FileSize == nil { @@ -2026,6 +2034,8 @@ type Media { type: MediaType! "The date the image was shot or the date it was imported as a fallback" date: Time! + "A short string that can be used to generate a blured version of the media, to show while the original is loading" + blurhash: String shares: [ShareToken!]! downloads: [MediaDownload!]! @@ -2997,6 +3007,21 @@ func (ec *executionContext) field_Query_user_args(ctx context.Context, rawArgs m return args, nil } +func (ec *executionContext) field___Field_args_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4394,6 +4419,38 @@ func (ec *executionContext) _Media_date(ctx context.Context, field graphql.Colle return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } +func (ec *executionContext) _Media_blurhash(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Media", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Blurhash, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _Media_shares(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -9351,6 +9408,41 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } +func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsRepeatable, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -9568,6 +9660,13 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col } ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field___Field_args_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children return obj.Args, nil @@ -10303,7 +10402,10 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co func (ec *executionContext) unmarshalInputOrdering(ctx context.Context, obj interface{}) (models.Ordering, error) { var it models.Ordering - var asMap = obj.(map[string]interface{}) + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } for k, v := range asMap { switch k { @@ -10331,7 +10433,10 @@ func (ec *executionContext) unmarshalInputOrdering(ctx context.Context, obj inte func (ec *executionContext) unmarshalInputPagination(ctx context.Context, obj interface{}) (models.Pagination, error) { var it models.Pagination - var asMap = obj.(map[string]interface{}) + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } for k, v := range asMap { switch k { @@ -10359,7 +10464,10 @@ func (ec *executionContext) unmarshalInputPagination(ctx context.Context, obj in func (ec *executionContext) unmarshalInputShareTokenCredentials(ctx context.Context, obj interface{}) (models.ShareTokenCredentials, error) { var it models.ShareTokenCredentials - var asMap = obj.(map[string]interface{}) + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } for k, v := range asMap { switch k { @@ -10397,7 +10505,6 @@ var albumImplementors = []string{"Album"} func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, obj *models.Album) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, albumImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10405,18 +10512,29 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob case "__typename": out.Values[i] = graphql.MarshalString("Album") case "id": - out.Values[i] = ec._Album_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Album_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "title": - out.Values[i] = ec._Album_title(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Album_title(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "media": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10427,10 +10545,16 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "subAlbums": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10441,12 +10565,23 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "parentAlbum": - out.Values[i] = ec._Album_parentAlbum(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Album_parentAlbum(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "owner": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10457,15 +10592,26 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "filePath": - out.Values[i] = ec._Album_filePath(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Album_filePath(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "thumbnail": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10473,10 +10619,16 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob }() res = ec._Album_thumbnail(ctx, field, obj) return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "path": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10487,10 +10639,16 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "shares": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10501,6 +10659,11 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) default: panic("unknown field " + strconv.Quote(field.Name)) @@ -10517,7 +10680,6 @@ var authorizeResultImplementors = []string{"AuthorizeResult"} func (ec *executionContext) _AuthorizeResult(ctx context.Context, sel ast.SelectionSet, obj *models.AuthorizeResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, authorizeResultImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10525,17 +10687,32 @@ func (ec *executionContext) _AuthorizeResult(ctx context.Context, sel ast.Select case "__typename": out.Values[i] = graphql.MarshalString("AuthorizeResult") case "success": - out.Values[i] = ec._AuthorizeResult_success(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AuthorizeResult_success(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "status": - out.Values[i] = ec._AuthorizeResult_status(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AuthorizeResult_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "token": - out.Values[i] = ec._AuthorizeResult_token(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AuthorizeResult_token(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -10551,7 +10728,6 @@ var coordinatesImplementors = []string{"Coordinates"} func (ec *executionContext) _Coordinates(ctx context.Context, sel ast.SelectionSet, obj *models.Coordinates) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, coordinatesImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10559,12 +10735,22 @@ func (ec *executionContext) _Coordinates(ctx context.Context, sel ast.SelectionS case "__typename": out.Values[i] = graphql.MarshalString("Coordinates") case "latitude": - out.Values[i] = ec._Coordinates_latitude(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Coordinates_latitude(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "longitude": - out.Values[i] = ec._Coordinates_longitude(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Coordinates_longitude(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -10583,7 +10769,6 @@ var faceGroupImplementors = []string{"FaceGroup"} func (ec *executionContext) _FaceGroup(ctx context.Context, sel ast.SelectionSet, obj *models.FaceGroup) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, faceGroupImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10591,15 +10776,26 @@ func (ec *executionContext) _FaceGroup(ctx context.Context, sel ast.SelectionSet case "__typename": out.Values[i] = graphql.MarshalString("FaceGroup") case "id": - out.Values[i] = ec._FaceGroup_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceGroup_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "label": - out.Values[i] = ec._FaceGroup_label(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceGroup_label(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "imageFaces": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10610,10 +10806,16 @@ func (ec *executionContext) _FaceGroup(ctx context.Context, sel ast.SelectionSet atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "imageFaceCount": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10624,6 +10826,11 @@ func (ec *executionContext) _FaceGroup(ctx context.Context, sel ast.SelectionSet atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) default: panic("unknown field " + strconv.Quote(field.Name)) @@ -10640,7 +10847,6 @@ var faceRectangleImplementors = []string{"FaceRectangle"} func (ec *executionContext) _FaceRectangle(ctx context.Context, sel ast.SelectionSet, obj *models.FaceRectangle) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, faceRectangleImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10648,22 +10854,42 @@ func (ec *executionContext) _FaceRectangle(ctx context.Context, sel ast.Selectio case "__typename": out.Values[i] = graphql.MarshalString("FaceRectangle") case "minX": - out.Values[i] = ec._FaceRectangle_minX(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceRectangle_minX(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "maxX": - out.Values[i] = ec._FaceRectangle_maxX(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceRectangle_maxX(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "minY": - out.Values[i] = ec._FaceRectangle_minY(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceRectangle_minY(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "maxY": - out.Values[i] = ec._FaceRectangle_maxY(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._FaceRectangle_maxY(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -10682,7 +10908,6 @@ var imageFaceImplementors = []string{"ImageFace"} func (ec *executionContext) _ImageFace(ctx context.Context, sel ast.SelectionSet, obj *models.ImageFace) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, imageFaceImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10690,13 +10915,19 @@ func (ec *executionContext) _ImageFace(ctx context.Context, sel ast.SelectionSet case "__typename": out.Values[i] = graphql.MarshalString("ImageFace") case "id": - out.Values[i] = ec._ImageFace_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ImageFace_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "media": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10707,15 +10938,26 @@ func (ec *executionContext) _ImageFace(ctx context.Context, sel ast.SelectionSet atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "rectangle": - out.Values[i] = ec._ImageFace_rectangle(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ImageFace_rectangle(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "faceGroup": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10726,6 +10968,11 @@ func (ec *executionContext) _ImageFace(ctx context.Context, sel ast.SelectionSet atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) default: panic("unknown field " + strconv.Quote(field.Name)) @@ -10742,7 +10989,6 @@ var mediaImplementors = []string{"Media"} func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, obj *models.Media) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mediaImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10750,23 +10996,39 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob case "__typename": out.Values[i] = graphql.MarshalString("Media") case "id": - out.Values[i] = ec._Media_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "title": - out.Values[i] = ec._Media_title(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_title(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "path": - out.Values[i] = ec._Media_path(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "thumbnail": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10774,10 +11036,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob }() res = ec._Media_thumbnail(ctx, field, obj) return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "highRes": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10785,10 +11053,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob }() res = ec._Media_highRes(ctx, field, obj) return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "videoWeb": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10796,10 +11070,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob }() res = ec._Media_videoWeb(ctx, field, obj) return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "album": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10810,10 +11090,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "exif": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10821,12 +11107,23 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob }() res = ec._Media_exif(ctx, field, obj) return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "videoMetadata": - out.Values[i] = ec._Media_videoMetadata(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_videoMetadata(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "favorite": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10837,10 +11134,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "type": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10851,15 +11154,33 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "date": - out.Values[i] = ec._Media_date(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_date(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } + case "blurhash": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Media_blurhash(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "shares": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10870,10 +11191,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "downloads": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10884,10 +11211,16 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "faces": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -10898,6 +11231,11 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) default: panic("unknown field " + strconv.Quote(field.Name)) @@ -10914,7 +11252,6 @@ var mediaDownloadImplementors = []string{"MediaDownload"} func (ec *executionContext) _MediaDownload(ctx context.Context, sel ast.SelectionSet, obj *models.MediaDownload) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mediaDownloadImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10922,12 +11259,22 @@ func (ec *executionContext) _MediaDownload(ctx context.Context, sel ast.Selectio case "__typename": out.Values[i] = graphql.MarshalString("MediaDownload") case "title": - out.Values[i] = ec._MediaDownload_title(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaDownload_title(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "mediaUrl": - out.Values[i] = ec._MediaDownload_mediaUrl(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaDownload_mediaUrl(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -10946,7 +11293,6 @@ var mediaEXIFImplementors = []string{"MediaEXIF"} func (ec *executionContext) _MediaEXIF(ctx context.Context, sel ast.SelectionSet, obj *models.MediaEXIF) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mediaEXIFImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -10954,37 +11300,102 @@ func (ec *executionContext) _MediaEXIF(ctx context.Context, sel ast.SelectionSet case "__typename": out.Values[i] = graphql.MarshalString("MediaEXIF") case "id": - out.Values[i] = ec._MediaEXIF_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "media": - out.Values[i] = ec._MediaEXIF_media(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_media(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "camera": - out.Values[i] = ec._MediaEXIF_camera(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_camera(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "maker": - out.Values[i] = ec._MediaEXIF_maker(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_maker(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "lens": - out.Values[i] = ec._MediaEXIF_lens(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_lens(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "dateShot": - out.Values[i] = ec._MediaEXIF_dateShot(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_dateShot(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "exposure": - out.Values[i] = ec._MediaEXIF_exposure(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_exposure(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "aperture": - out.Values[i] = ec._MediaEXIF_aperture(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_aperture(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "iso": - out.Values[i] = ec._MediaEXIF_iso(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_iso(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "focalLength": - out.Values[i] = ec._MediaEXIF_focalLength(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_focalLength(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "flash": - out.Values[i] = ec._MediaEXIF_flash(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_flash(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "exposureProgram": - out.Values[i] = ec._MediaEXIF_exposureProgram(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_exposureProgram(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "coordinates": - out.Values[i] = ec._MediaEXIF_coordinates(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_coordinates(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11000,7 +11411,6 @@ var mediaURLImplementors = []string{"MediaURL"} func (ec *executionContext) _MediaURL(ctx context.Context, sel ast.SelectionSet, obj *models.MediaURL) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mediaURLImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11008,22 +11418,42 @@ func (ec *executionContext) _MediaURL(ctx context.Context, sel ast.SelectionSet, case "__typename": out.Values[i] = graphql.MarshalString("MediaURL") case "url": - out.Values[i] = ec._MediaURL_url(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaURL_url(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "width": - out.Values[i] = ec._MediaURL_width(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaURL_width(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "height": - out.Values[i] = ec._MediaURL_height(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaURL_height(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "fileSize": - out.Values[i] = ec._MediaURL_fileSize(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaURL_fileSize(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -11042,7 +11472,6 @@ var mutationImplementors = []string{"Mutation"} func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: "Mutation", }) @@ -11050,117 +11479,242 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Mutation") case "authorizeUser": - out.Values[i] = ec._Mutation_authorizeUser(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_authorizeUser(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "initialSetupWizard": - out.Values[i] = ec._Mutation_initialSetupWizard(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_initialSetupWizard(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + case "scanAll": - out.Values[i] = ec._Mutation_scanAll(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_scanAll(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "scanUser": - out.Values[i] = ec._Mutation_scanUser(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_scanUser(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "shareAlbum": - out.Values[i] = ec._Mutation_shareAlbum(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_shareAlbum(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "shareMedia": - out.Values[i] = ec._Mutation_shareMedia(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_shareMedia(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "deleteShareToken": - out.Values[i] = ec._Mutation_deleteShareToken(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteShareToken(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "protectShareToken": - out.Values[i] = ec._Mutation_protectShareToken(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_protectShareToken(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "favoriteMedia": - out.Values[i] = ec._Mutation_favoriteMedia(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_favoriteMedia(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "updateUser": - out.Values[i] = ec._Mutation_updateUser(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateUser(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "createUser": - out.Values[i] = ec._Mutation_createUser(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createUser(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "deleteUser": - out.Values[i] = ec._Mutation_deleteUser(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteUser(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "userAddRootPath": - out.Values[i] = ec._Mutation_userAddRootPath(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_userAddRootPath(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + case "userRemoveRootAlbum": - out.Values[i] = ec._Mutation_userRemoveRootAlbum(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_userRemoveRootAlbum(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + case "setPeriodicScanInterval": - out.Values[i] = ec._Mutation_setPeriodicScanInterval(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setPeriodicScanInterval(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "setScannerConcurrentWorkers": - out.Values[i] = ec._Mutation_setScannerConcurrentWorkers(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setScannerConcurrentWorkers(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "changeUserPreferences": - out.Values[i] = ec._Mutation_changeUserPreferences(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_changeUserPreferences(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "resetAlbumCover": - out.Values[i] = ec._Mutation_resetAlbumCover(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_resetAlbumCover(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "setAlbumCover": - out.Values[i] = ec._Mutation_setAlbumCover(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setAlbumCover(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "setFaceGroupLabel": - out.Values[i] = ec._Mutation_setFaceGroupLabel(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setFaceGroupLabel(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "combineFaceGroups": - out.Values[i] = ec._Mutation_combineFaceGroups(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_combineFaceGroups(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "moveImageFaces": - out.Values[i] = ec._Mutation_moveImageFaces(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_moveImageFaces(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "recognizeUnlabeledFaces": - out.Values[i] = ec._Mutation_recognizeUnlabeledFaces(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_recognizeUnlabeledFaces(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } case "detachImageFaces": - out.Values[i] = ec._Mutation_detachImageFaces(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_detachImageFaces(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } @@ -11179,7 +11733,6 @@ var notificationImplementors = []string{"Notification"} func (ec *executionContext) _Notification(ctx context.Context, sel ast.SelectionSet, obj *models.Notification) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, notificationImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11187,39 +11740,79 @@ func (ec *executionContext) _Notification(ctx context.Context, sel ast.Selection case "__typename": out.Values[i] = graphql.MarshalString("Notification") case "key": - out.Values[i] = ec._Notification_key(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_key(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "type": - out.Values[i] = ec._Notification_type(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "header": - out.Values[i] = ec._Notification_header(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_header(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "content": - out.Values[i] = ec._Notification_content(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_content(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "progress": - out.Values[i] = ec._Notification_progress(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_progress(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "positive": - out.Values[i] = ec._Notification_positive(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_positive(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "negative": - out.Values[i] = ec._Notification_negative(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_negative(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "timeout": - out.Values[i] = ec._Notification_timeout(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Notification_timeout(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11235,7 +11828,6 @@ var queryImplementors = []string{"Query"} func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: "Query", }) @@ -11243,12 +11835,18 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") case "siteInfo": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11259,10 +11857,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "user": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11273,10 +11880,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myUser": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11287,10 +11903,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myUserPreferences": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11301,10 +11926,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myAlbums": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11315,10 +11949,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "album": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11329,10 +11972,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myMedia": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11343,10 +11995,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "media": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11357,10 +12018,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "mediaList": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11371,10 +12041,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myTimeline": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11385,10 +12064,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myMediaGeoJson": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11399,10 +12087,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "mapboxToken": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11410,10 +12107,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr }() res = ec._Query_mapboxToken(ctx, field) return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "shareToken": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11424,10 +12130,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "shareTokenValidatePassword": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11438,10 +12153,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "search": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11452,10 +12176,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "myFaceGroups": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11466,10 +12199,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "faceGroup": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11480,11 +12222,29 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr atomic.AddUint32(&invalids, 1) } return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) }) case "__type": - out.Values[i] = ec._Query___type(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___type(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + case "__schema": - out.Values[i] = ec._Query___schema(ctx, field) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___schema(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11500,7 +12260,6 @@ var scannerResultImplementors = []string{"ScannerResult"} func (ec *executionContext) _ScannerResult(ctx context.Context, sel ast.SelectionSet, obj *models.ScannerResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, scannerResultImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11508,19 +12267,39 @@ func (ec *executionContext) _ScannerResult(ctx context.Context, sel ast.Selectio case "__typename": out.Values[i] = graphql.MarshalString("ScannerResult") case "finished": - out.Values[i] = ec._ScannerResult_finished(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ScannerResult_finished(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "success": - out.Values[i] = ec._ScannerResult_success(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ScannerResult_success(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "progress": - out.Values[i] = ec._ScannerResult_progress(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ScannerResult_progress(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "message": - out.Values[i] = ec._ScannerResult_message(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ScannerResult_message(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11536,7 +12315,6 @@ var searchResultImplementors = []string{"SearchResult"} func (ec *executionContext) _SearchResult(ctx context.Context, sel ast.SelectionSet, obj *models.SearchResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, searchResultImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11544,17 +12322,32 @@ func (ec *executionContext) _SearchResult(ctx context.Context, sel ast.Selection case "__typename": out.Values[i] = graphql.MarshalString("SearchResult") case "query": - out.Values[i] = ec._SearchResult_query(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SearchResult_query(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "albums": - out.Values[i] = ec._SearchResult_albums(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SearchResult_albums(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "media": - out.Values[i] = ec._SearchResult_media(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SearchResult_media(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -11573,7 +12366,6 @@ var shareTokenImplementors = []string{"ShareToken"} func (ec *executionContext) _ShareToken(ctx context.Context, sel ast.SelectionSet, obj *models.ShareToken) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, shareTokenImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11581,25 +12373,46 @@ func (ec *executionContext) _ShareToken(ctx context.Context, sel ast.SelectionSe case "__typename": out.Values[i] = graphql.MarshalString("ShareToken") case "id": - out.Values[i] = ec._ShareToken_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "token": - out.Values[i] = ec._ShareToken_token(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_token(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "owner": - out.Values[i] = ec._ShareToken_owner(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_owner(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "expire": - out.Values[i] = ec._ShareToken_expire(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_expire(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "hasPassword": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11610,11 +12423,26 @@ func (ec *executionContext) _ShareToken(ctx context.Context, sel ast.SelectionSe atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "album": - out.Values[i] = ec._ShareToken_album(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_album(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "media": - out.Values[i] = ec._ShareToken_media(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ShareToken_media(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11630,7 +12458,6 @@ var siteInfoImplementors = []string{"SiteInfo"} func (ec *executionContext) _SiteInfo(ctx context.Context, sel ast.SelectionSet, obj *models.SiteInfo) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, siteInfoImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11638,13 +12465,19 @@ func (ec *executionContext) _SiteInfo(ctx context.Context, sel ast.SelectionSet, case "__typename": out.Values[i] = graphql.MarshalString("SiteInfo") case "initialSetup": - out.Values[i] = ec._SiteInfo_initialSetup(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SiteInfo_initialSetup(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "faceDetectionEnabled": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11655,14 +12488,29 @@ func (ec *executionContext) _SiteInfo(ctx context.Context, sel ast.SelectionSet, atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "periodicScanInterval": - out.Values[i] = ec._SiteInfo_periodicScanInterval(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SiteInfo_periodicScanInterval(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "concurrentWorkers": - out.Values[i] = ec._SiteInfo_concurrentWorkers(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._SiteInfo_concurrentWorkers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } @@ -11701,7 +12549,6 @@ var timelineGroupImplementors = []string{"TimelineGroup"} func (ec *executionContext) _TimelineGroup(ctx context.Context, sel ast.SelectionSet, obj *models.TimelineGroup) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, timelineGroupImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11709,22 +12556,42 @@ func (ec *executionContext) _TimelineGroup(ctx context.Context, sel ast.Selectio case "__typename": out.Values[i] = graphql.MarshalString("TimelineGroup") case "album": - out.Values[i] = ec._TimelineGroup_album(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._TimelineGroup_album(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "media": - out.Values[i] = ec._TimelineGroup_media(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._TimelineGroup_media(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "mediaTotal": - out.Values[i] = ec._TimelineGroup_mediaTotal(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._TimelineGroup_mediaTotal(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "date": - out.Values[i] = ec._TimelineGroup_date(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._TimelineGroup_date(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -11743,7 +12610,6 @@ var userImplementors = []string{"User"} func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *models.User) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11751,18 +12617,29 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj case "__typename": out.Values[i] = graphql.MarshalString("User") case "id": - out.Values[i] = ec._User_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._User_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "username": - out.Values[i] = ec._User_username(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._User_username(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } case "albums": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11773,10 +12650,16 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "rootAlbums": field := field - out.Concurrently(i, func() (res graphql.Marshaler) { + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -11787,9 +12670,19 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj atomic.AddUint32(&invalids, 1) } return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + }) case "admin": - out.Values[i] = ec._User_admin(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._User_admin(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } @@ -11808,7 +12701,6 @@ var userPreferencesImplementors = []string{"UserPreferences"} func (ec *executionContext) _UserPreferences(ctx context.Context, sel ast.SelectionSet, obj *models.UserPreferences) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userPreferencesImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11816,12 +12708,22 @@ func (ec *executionContext) _UserPreferences(ctx context.Context, sel ast.Select case "__typename": out.Values[i] = graphql.MarshalString("UserPreferences") case "id": - out.Values[i] = ec._UserPreferences_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._UserPreferences_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "language": - out.Values[i] = ec._UserPreferences_language(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._UserPreferences_language(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11837,7 +12739,6 @@ var videoMetadataImplementors = []string{"VideoMetadata"} func (ec *executionContext) _VideoMetadata(ctx context.Context, sel ast.SelectionSet, obj *models.VideoMetadata) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, videoMetadataImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11845,40 +12746,90 @@ func (ec *executionContext) _VideoMetadata(ctx context.Context, sel ast.Selectio case "__typename": out.Values[i] = graphql.MarshalString("VideoMetadata") case "id": - out.Values[i] = ec._VideoMetadata_id(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "media": - out.Values[i] = ec._VideoMetadata_media(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_media(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "width": - out.Values[i] = ec._VideoMetadata_width(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_width(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "height": - out.Values[i] = ec._VideoMetadata_height(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_height(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "duration": - out.Values[i] = ec._VideoMetadata_duration(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_duration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "codec": - out.Values[i] = ec._VideoMetadata_codec(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_codec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "framerate": - out.Values[i] = ec._VideoMetadata_framerate(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_framerate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "bitrate": - out.Values[i] = ec._VideoMetadata_bitrate(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_bitrate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "colorProfile": - out.Values[i] = ec._VideoMetadata_colorProfile(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_colorProfile(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "audio": - out.Values[i] = ec._VideoMetadata_audio(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._VideoMetadata_audio(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11894,7 +12845,6 @@ var __DirectiveImplementors = []string{"__Directive"} func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11902,19 +12852,49 @@ func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionS case "__typename": out.Values[i] = graphql.MarshalString("__Directive") case "name": - out.Values[i] = ec.___Directive_name(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "description": - out.Values[i] = ec.___Directive_description(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "locations": - out.Values[i] = ec.___Directive_locations(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_locations(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "args": - out.Values[i] = ec.___Directive_args(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_args(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "isRepeatable": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_isRepeatable(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -11933,7 +12913,6 @@ var __EnumValueImplementors = []string{"__EnumValue"} func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11941,19 +12920,39 @@ func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionS case "__typename": out.Values[i] = graphql.MarshalString("__EnumValue") case "name": - out.Values[i] = ec.___EnumValue_name(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "description": - out.Values[i] = ec.___EnumValue_description(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "isDeprecated": - out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_isDeprecated(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "deprecationReason": - out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_deprecationReason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11969,7 +12968,6 @@ var __FieldImplementors = []string{"__Field"} func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -11977,29 +12975,59 @@ func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, case "__typename": out.Values[i] = graphql.MarshalString("__Field") case "name": - out.Values[i] = ec.___Field_name(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "description": - out.Values[i] = ec.___Field_description(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "args": - out.Values[i] = ec.___Field_args(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_args(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "type": - out.Values[i] = ec.___Field_type(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "isDeprecated": - out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_isDeprecated(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "deprecationReason": - out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_deprecationReason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -12015,7 +13043,6 @@ var __InputValueImplementors = []string{"__InputValue"} func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -12023,19 +13050,39 @@ func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.Selection case "__typename": out.Values[i] = graphql.MarshalString("__InputValue") case "name": - out.Values[i] = ec.___InputValue_name(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "description": - out.Values[i] = ec.___InputValue_description(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "type": - out.Values[i] = ec.___InputValue_type(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "defaultValue": - out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_defaultValue(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -12051,7 +13098,6 @@ var __SchemaImplementors = []string{"__Schema"} func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -12059,21 +13105,46 @@ func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, case "__typename": out.Values[i] = graphql.MarshalString("__Schema") case "types": - out.Values[i] = ec.___Schema_types(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_types(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "queryType": - out.Values[i] = ec.___Schema_queryType(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_queryType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "mutationType": - out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_mutationType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "subscriptionType": - out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_subscriptionType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "directives": - out.Values[i] = ec.___Schema_directives(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_directives(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } @@ -12092,7 +13163,6 @@ var __TypeImplementors = []string{"__Type"} func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) - out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { @@ -12100,26 +13170,71 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o case "__typename": out.Values[i] = graphql.MarshalString("__Type") case "kind": - out.Values[i] = ec.___Type_kind(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + if out.Values[i] == graphql.Null { invalids++ } case "name": - out.Values[i] = ec.___Type_name(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "description": - out.Values[i] = ec.___Type_description(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "fields": - out.Values[i] = ec.___Type_fields(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_fields(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "interfaces": - out.Values[i] = ec.___Type_interfaces(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_interfaces(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "possibleTypes": - out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_possibleTypes(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "enumValues": - out.Values[i] = ec.___Type_enumValues(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_enumValues(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "inputFields": - out.Values[i] = ec.___Type_inputFields(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_inputFields(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "ofType": - out.Values[i] = ec.___Type_ofType(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_ofType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -12173,6 +13288,13 @@ func (ec *executionContext) marshalNAlbum2ᚕᚖgithubᚗcomᚋphotoviewᚋphoto } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12274,6 +13396,13 @@ func (ec *executionContext) marshalNFaceGroup2ᚕᚖgithubᚗcomᚋphotoviewᚋp } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12292,18 +13421,18 @@ func (ec *executionContext) marshalNFaceRectangle2githubᚗcomᚋphotoviewᚋpho } func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { - res, err := graphql.UnmarshalFloat(v) + res, err := graphql.UnmarshalFloatContext(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { - res := graphql.MarshalFloat(v) + res := graphql.MarshalFloatContext(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "must not be null") } } - return res + return graphql.WrapContextMarshaler(ctx, res) } func (ec *executionContext) unmarshalNID2int(ctx context.Context, v interface{}) (int, error) { @@ -12324,11 +13453,7 @@ func (ec *executionContext) marshalNID2int(ctx context.Context, sel ast.Selectio func (ec *executionContext) unmarshalNID2ᚕintᚄ(ctx context.Context, v interface{}) ([]int, error) { var vSlice []interface{} if v != nil { - if tmp1, ok := v.([]interface{}); ok { - vSlice = tmp1 - } else { - vSlice = []interface{}{v} - } + vSlice = graphql.CoerceList(v) } var err error res := make([]int, len(vSlice)) @@ -12348,6 +13473,12 @@ func (ec *executionContext) marshalNID2ᚕintᚄ(ctx context.Context, sel ast.Se ret[i] = ec.marshalNID2int(ctx, sel, v[i]) } + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12385,6 +13516,13 @@ func (ec *executionContext) marshalNImageFace2ᚕᚖgithubᚗcomᚋphotoviewᚋp } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12466,6 +13604,13 @@ func (ec *executionContext) marshalNMedia2ᚕᚖgithubᚗcomᚋphotoviewᚋphoto } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12513,6 +13658,13 @@ func (ec *executionContext) marshalNMediaDownload2ᚕᚖgithubᚗcomᚋphotoview } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12642,6 +13794,13 @@ func (ec *executionContext) marshalNShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋ } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12742,6 +13901,13 @@ func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋphotoviewᚋphotov } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12807,6 +13973,13 @@ func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgq } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12828,11 +14001,7 @@ func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Conte func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { var vSlice []interface{} if v != nil { - if tmp1, ok := v.([]interface{}); ok { - vSlice = tmp1 - } else { - vSlice = []interface{}{v} - } + vSlice = graphql.CoerceList(v) } var err error res := make([]string, len(vSlice)) @@ -12880,6 +14049,13 @@ func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12929,6 +14105,13 @@ func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋg } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -12970,6 +14153,13 @@ func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgen } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -13018,7 +14208,8 @@ func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interf } func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - return graphql.MarshalBoolean(v) + res := graphql.MarshalBoolean(v) + return res } func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { @@ -13033,7 +14224,8 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast if v == nil { return graphql.Null } - return graphql.MarshalBoolean(*v) + res := graphql.MarshalBoolean(*v) + return res } func (ec *executionContext) marshalOCoordinates2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐCoordinates(ctx context.Context, sel ast.SelectionSet, v *models.Coordinates) graphql.Marshaler { @@ -13047,7 +14239,7 @@ func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v in if v == nil { return nil, nil } - res, err := graphql.UnmarshalFloat(v) + res, err := graphql.UnmarshalFloatContext(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } @@ -13055,7 +14247,8 @@ func (ec *executionContext) marshalOFloat2ᚖfloat64(ctx context.Context, sel as if v == nil { return graphql.Null } - return graphql.MarshalFloat(*v) + res := graphql.MarshalFloatContext(*v) + return graphql.WrapContextMarshaler(ctx, res) } func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { @@ -13070,7 +14263,8 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele if v == nil { return graphql.Null } - return graphql.MarshalInt(*v) + res := graphql.MarshalInt(*v) + return res } func (ec *executionContext) unmarshalOInt2ᚖint64(ctx context.Context, v interface{}) (*int64, error) { @@ -13085,7 +14279,8 @@ func (ec *executionContext) marshalOInt2ᚖint64(ctx context.Context, sel ast.Se if v == nil { return graphql.Null } - return graphql.MarshalInt64(*v) + res := graphql.MarshalInt64(*v) + return res } func (ec *executionContext) unmarshalOLanguageTranslation2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐLanguageTranslation(ctx context.Context, v interface{}) (*models.LanguageTranslation, error) { @@ -13171,7 +14366,8 @@ func (ec *executionContext) unmarshalOString2string(ctx context.Context, v inter } func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - return graphql.MarshalString(v) + res := graphql.MarshalString(v) + return res } func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { @@ -13186,7 +14382,8 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as if v == nil { return graphql.Null } - return graphql.MarshalString(*v) + res := graphql.MarshalString(*v) + return res } func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { @@ -13201,7 +14398,8 @@ func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel if v == nil { return graphql.Null } - return graphql.MarshalTime(*v) + res := graphql.MarshalTime(*v) + return res } func (ec *executionContext) marshalOVideoMetadata2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐVideoMetadata(ctx context.Context, sel ast.SelectionSet, v *models.VideoMetadata) graphql.Marshaler { @@ -13248,6 +14446,13 @@ func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgq } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -13288,6 +14493,13 @@ func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgen } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -13328,6 +14540,13 @@ func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋg } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } @@ -13375,6 +14594,13 @@ func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgen } wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + return ret } diff --git a/api/graphql/models/media.go b/api/graphql/models/media.go index 3a7e1cb..a413b58 100644 --- a/api/graphql/models/media.go +++ b/api/graphql/models/media.go @@ -50,7 +50,7 @@ func (m *Media) Date() time.Time { return m.DateShot } -func (m *Media) Thumbnail() (*MediaURL, error) { +func (m *Media) GetThumbnail() (*MediaURL, error) { if len(m.MediaURL) == 0 { return nil, errors.New("media.MediaURL is empty") } diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 36a2df7..0f9e339 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -328,6 +328,8 @@ type Media { type: MediaType! "The date the image was shot or the date it was imported as a fallback" date: Time! + "A short string that can be used to generate a blured version of the media, to show while the original is loading" + blurhash: String shares: [ShareToken!]! downloads: [MediaDownload!]! diff --git a/api/scanner/thumbnail_blurhash.go b/api/scanner/thumbnail_blurhash.go index 066ad82..8df0705 100644 --- a/api/scanner/thumbnail_blurhash.go +++ b/api/scanner/thumbnail_blurhash.go @@ -24,14 +24,14 @@ func GenerateBlurhashes(db *gorm.DB) error { Where("blurhash IS NULL"). Where("media_urls.purpose = 'thumbnail' OR media_urls.purpose = 'video-thumbnail'") - err := query.FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error { + err := query.FindInBatches(&results, 50, func(tx *gorm.DB, batch int) error { log.Printf("generating %d blurhashes", len(results)) hashes := make([]*string, len(results)) for i, row := range results { - thumbnail, err := row.Thumbnail() + thumbnail, err := row.GetThumbnail() if err != nil { log.Printf("failed to get thumbnail for media to generate blurhash (%d): %v", row.ID, err) processErrors = append(processErrors, err) diff --git a/ui/package-lock.json b/ui/package-lock.json index d74d130..ecd3985 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -26,6 +26,7 @@ "@types/url-join": "^4.0.1", "autoprefixer": "^9.8.6", "babel-plugin-graphql-tag": "^3.3.0", + "blurhash": "^1.1.4", "classnames": "^2.3.1", "connect-history-api-fallback": "^1.6.0", "copy-to-clipboard": "^3.3.1", @@ -38,6 +39,7 @@ "prettier": "^2.5.1", "prop-types": "^15.8.1", "react": "^17.0.2", + "react-blurhash": "^0.1.3", "react-dom": "^17.0.2", "react-helmet": "^6.1.0", "react-hook-form": "^7.25.3", @@ -124,6 +126,53 @@ "npm": ">=6" } }, + "node_modules/@apollographql/graphql-language-service-interface": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-interface/-/graphql-language-service-interface-2.0.2.tgz", + "integrity": "sha512-28wePK0hlIVjgmvMXMAUq8qRSjz9O+6lqFp4PzOTHtfJfSsjVe9EfjF98zTpHsTgT3HcOxmbqDZZy8jlXtOqEA==", + "dev": true, + "dependencies": { + "@apollographql/graphql-language-service-parser": "^2.0.0", + "@apollographql/graphql-language-service-types": "^2.0.0", + "@apollographql/graphql-language-service-utils": "^2.0.2" + }, + "peerDependencies": { + "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" + } + }, + "node_modules/@apollographql/graphql-language-service-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-parser/-/graphql-language-service-parser-2.0.2.tgz", + "integrity": "sha512-rpTPrEJu1PMaRQxz5P8BZWsixNNhYloS0H0dwTxNBuE3qctbARvR7o8UCKLsmKgTbo+cz3T3a6IAsWlkHgMWGg==", + "dev": true, + "dependencies": { + "@apollographql/graphql-language-service-types": "^2.0.0" + }, + "peerDependencies": { + "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" + } + }, + "node_modules/@apollographql/graphql-language-service-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-types/-/graphql-language-service-types-2.0.2.tgz", + "integrity": "sha512-vE+Dz8pG+Xa1Z2nMl82LoO66lQ6JqBUjaXqLDvS3eMjvA3N4hf+YUDOWfPdNZ0zjhHhHXzUIIZCkax6bXfFbzQ==", + "dev": true, + "peerDependencies": { + "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" + } + }, + "node_modules/@apollographql/graphql-language-service-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-utils/-/graphql-language-service-utils-2.0.2.tgz", + "integrity": "sha512-fDj5rWlTi/czvUS5t7V7I45Ai6bOO3Z7JARYj21Y2xxfbRGtJi6h8FvLX0N/EbzQgo/fiZc/HAhtfwn+OCjD7A==", + "dev": true, + "dependencies": { + "@apollographql/graphql-language-service-types": "^2.0.0" + }, + "peerDependencies": { + "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", @@ -2800,9 +2849,9 @@ "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=" }, "node_modules/@mapbox/tiny-sdf": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.4.tgz", - "integrity": "sha512-CBtL2rhZiYmdIryksp0zh4Mmx54iClYfNb0mpYeHrZnq4z84lVjre7LBWGPEjWspEn6AiF0lxC1HaZDye89m3g==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.5.tgz", + "integrity": "sha512-OhXt2lS//WpLdkqrzo/KwB7SRD8AiNTFFzuo9n14IBupzIMa67yGItcK7I2W9D8Ghpa4T04Sw9FWsKCJG50Bxw==" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.0", @@ -3488,6 +3537,7 @@ "version": "4.9.3", "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.3.tgz", "integrity": "sha512-/1owvF0SZ5Gn54cgrikJ0QskgTzeg30HGjkmjFoaHDJzAqFpuX1DBpFR8aLvsE1J5s9MgeYRENQK4BFwOag5VA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "@oclif/errors": "^1.2.2", @@ -4582,9 +4632,9 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "node_modules/@types/node": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.13.tgz", - "integrity": "sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw==" + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.14.tgz", + "integrity": "sha512-SbjLmERksKOGzWzPNuW7fJM7fk3YXVTFiZWB/Hs99gwhk+/dnrQRPBQjPW9aO+fi1tAffi9PrwFvsmOKmDTyng==" }, "node_modules/@types/node-fetch": { "version": "2.5.12", @@ -5724,53 +5774,6 @@ "npm": ">=6" } }, - "node_modules/apollo-language-server/node_modules/@apollographql/graphql-language-service-interface": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-interface/-/graphql-language-service-interface-2.0.2.tgz", - "integrity": "sha512-28wePK0hlIVjgmvMXMAUq8qRSjz9O+6lqFp4PzOTHtfJfSsjVe9EfjF98zTpHsTgT3HcOxmbqDZZy8jlXtOqEA==", - "dev": true, - "dependencies": { - "@apollographql/graphql-language-service-parser": "^2.0.0", - "@apollographql/graphql-language-service-types": "^2.0.0", - "@apollographql/graphql-language-service-utils": "^2.0.2" - }, - "peerDependencies": { - "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" - } - }, - "node_modules/apollo-language-server/node_modules/@apollographql/graphql-language-service-parser": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-parser/-/graphql-language-service-parser-2.0.2.tgz", - "integrity": "sha512-rpTPrEJu1PMaRQxz5P8BZWsixNNhYloS0H0dwTxNBuE3qctbARvR7o8UCKLsmKgTbo+cz3T3a6IAsWlkHgMWGg==", - "dev": true, - "dependencies": { - "@apollographql/graphql-language-service-types": "^2.0.0" - }, - "peerDependencies": { - "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" - } - }, - "node_modules/apollo-language-server/node_modules/@apollographql/graphql-language-service-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-types/-/graphql-language-service-types-2.0.2.tgz", - "integrity": "sha512-vE+Dz8pG+Xa1Z2nMl82LoO66lQ6JqBUjaXqLDvS3eMjvA3N4hf+YUDOWfPdNZ0zjhHhHXzUIIZCkax6bXfFbzQ==", - "dev": true, - "peerDependencies": { - "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" - } - }, - "node_modules/apollo-language-server/node_modules/@apollographql/graphql-language-service-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-utils/-/graphql-language-service-utils-2.0.2.tgz", - "integrity": "sha512-fDj5rWlTi/czvUS5t7V7I45Ai6bOO3Z7JARYj21Y2xxfbRGtJi6h8FvLX0N/EbzQgo/fiZc/HAhtfwn+OCjD7A==", - "dev": true, - "dependencies": { - "@apollographql/graphql-language-service-types": "^2.0.0" - }, - "peerDependencies": { - "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" - } - }, "node_modules/apollo-language-server/node_modules/@endemolshinegroup/cosmiconfig-typescript-loader": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.2.tgz", @@ -5811,18 +5814,6 @@ "node": ">=4" } }, - "node_modules/apollo-language-server/node_modules/graphql": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.7.0.tgz", - "integrity": "sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA==", - "dev": true, - "dependencies": { - "iterall": "^1.2.2" - }, - "engines": { - "node": ">= 6.x" - } - }, "node_modules/apollo-language-server/node_modules/import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", @@ -6395,11 +6386,6 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } }, - "node_modules/autoprefixer/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, "node_modules/await-to-js": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-2.1.1.tgz", @@ -6410,9 +6396,9 @@ } }, "node_modules/axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.0.tgz", + "integrity": "sha512-btWy2rze3NnxSSxb7LtNhPYYFrRoFBfjiGzmSc/5Hu47wApO2KNXjP/w7Nv2Uz/Fyr/pfEiwOkcXhDxu0jz5FA==", "engines": { "node": ">=4" } @@ -6972,6 +6958,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "node_modules/blurhash": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-1.1.4.tgz", + "integrity": "sha512-MXIPz6zwYUKayju+Uidf83KhH0vodZfeRl6Ich8Gu+KGl0JgKiFq9LsfqV7cVU5fKD/AotmduZqvOfrGKOfTaA==" + }, "node_modules/bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", @@ -7270,6 +7261,11 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/browserslist/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -7936,6 +7932,7 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.3.tgz", "integrity": "sha512-/oDU4v8BiDjX2OKcSunGH0iGDiEtj2rZaGyqNuv9IT4CgcSMyVWAMfn0+rEHaOc4n9ka78B0wo1+N1QX89f7mw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "@oclif/command": "^1.6.0", @@ -8597,9 +8594,9 @@ } }, "node_modules/core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.0.tgz", + "integrity": "sha512-YUdI3fFu4TF/2WykQ2xzSiTQdldLB4KVuL9WeAy5XONZYt5Cun/fpQvctoKbCgvPhmzADeesTk/j2Rdx77AcKQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -8607,9 +8604,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.3.tgz", - "integrity": "sha512-c8M5h0IkNZ+I92QhIpuSijOxGAcj3lgpsWdkCqmUTZNwidujF4r3pi6x1DCN+Vcs5qTS2XWWMfWSuCqyupX8gw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "dependencies": { "browserslist": "^4.19.1", "semver": "7.0.0" @@ -8628,9 +8625,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.20.3.tgz", - "integrity": "sha512-Q2H6tQ5MtPtcC7f3HxJ48i4Q7T9ybPKgvWyuH7JXIoNa2pm0KuBnycsET/qw1SLLZYfbsbrZQNMeIOClb+6WIA==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.0.tgz", + "integrity": "sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -9938,9 +9935,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.57", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.57.tgz", - "integrity": "sha512-FNC+P5K1n6pF+M0zIK+gFCoXcJhhzDViL3DRIGy2Fv5PohuSES1JHR7T+GlwxSxlzx4yYbsuzCZvHxcBSRCIOw==" + "version": "1.4.60", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.60.tgz", + "integrity": "sha512-h53hbEiKC6hijelDgxgkgAUC3PKyR7TmIfvjHnBjUGPMg/3sBuTyG6eDormw+lY24uUJvHkUPzB8dpK8b2u3Sw==" }, "node_modules/elegant-spinner": { "version": "1.0.1", @@ -16992,9 +16989,9 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.2.tgz", - "integrity": "sha512-gtw4Cbj01SuVSfAOXC6ivd/7VKHTj51yj5xV8TgktFmYNMsZzXuSd5/brqJEA93v63wL7R6iDlunMANOechC0A==", + "version": "12.3.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.3.tgz", + "integrity": "sha512-OqcLsqcPOqzvsfkxjeBpZylgJ3SRG1RYqc9LxC6tkt6tNsq1bNVkAixBwX09f6CobcHswzqVOCBpFR1Fck0+ag==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", @@ -17233,9 +17230,9 @@ } }, "node_modules/listr2": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.1.tgz", - "integrity": "sha512-D65Nl+zyYHL2jQBGmxtH/pU8koPZo5C8iCNE8EoB04RwPgQG1wuaKwVbeZv9LJpiH4Nxs0FCp+nNcG8OqpniiA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.2.tgz", + "integrity": "sha512-YcgwfCWpvPbj9FLUGqvdFvd3hrFWKpOeuXznRgfWEJ7RNr8b/IKKIKZABHx3aU+4CWN/iSAFFSReziQG6vTeIA==", "dev": true, "dependencies": { "cli-truncate": "^2.1.0", @@ -17855,9 +17852,9 @@ } }, "node_modules/mapbox-gl": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.6.1.tgz", - "integrity": "sha512-faGbSZfcFuZ4GWwkWnJrRD3oICZAt/mVKnGuOmeBobCj9onfTRz270qSoOXeRBKd3po5VA2cCPI91YwA8DsAoQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.7.0.tgz", + "integrity": "sha512-7sNoQIpizMjoQkFIcxpWzFCcMd8GJFN0Po00oFZGm1X7xS5XMrzwu+ClfO/ehZqKLa9IS7E3Pj0e2PT+9KeqaA==", "dependencies": { "@mapbox/geojson-rewind": "^0.5.1", "@mapbox/geojson-types": "^1.0.2", @@ -19608,9 +19605,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -20955,14 +20952,19 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/postcss-safe-parser/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "node_modules/postcss-safe-parser/node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dependencies": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -21051,11 +21053,6 @@ "node": ">=6.14.4" } }, - "node_modules/postcss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, "node_modules/postcss/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -21310,14 +21307,19 @@ "purgecss": "bin/purgecss.js" } }, + "node_modules/purgecss/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "node_modules/purgecss/node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dependencies": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -21532,6 +21534,15 @@ "node": ">=10" } }, + "node_modules/react-blurhash": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/react-blurhash/-/react-blurhash-0.1.3.tgz", + "integrity": "sha512-Q9lqbXg92NU6/2DoIl/cBM8YWL+Z4X66OiG4aT9ozOgjBwx104LHFCH5stf6aF+s0Q9Wf310Ul+dG+VXJltmPg==", + "peerDependencies": { + "blurhash": "^1.1.1", + "react": ">=15" + } + }, "node_modules/react-dev-utils": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", @@ -28618,6 +28629,42 @@ "integrity": "sha512-KxZiw0Us3k1d0YkJDhOpVH5rJ+mBfjXcgoRoCcslbgirjgLotKMzOcx4PZ7YTEvvEROmvG7X3Aon41GvMmyGsw==", "dev": true }, + "@apollographql/graphql-language-service-interface": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-interface/-/graphql-language-service-interface-2.0.2.tgz", + "integrity": "sha512-28wePK0hlIVjgmvMXMAUq8qRSjz9O+6lqFp4PzOTHtfJfSsjVe9EfjF98zTpHsTgT3HcOxmbqDZZy8jlXtOqEA==", + "dev": true, + "requires": { + "@apollographql/graphql-language-service-parser": "^2.0.0", + "@apollographql/graphql-language-service-types": "^2.0.0", + "@apollographql/graphql-language-service-utils": "^2.0.2" + } + }, + "@apollographql/graphql-language-service-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-parser/-/graphql-language-service-parser-2.0.2.tgz", + "integrity": "sha512-rpTPrEJu1PMaRQxz5P8BZWsixNNhYloS0H0dwTxNBuE3qctbARvR7o8UCKLsmKgTbo+cz3T3a6IAsWlkHgMWGg==", + "dev": true, + "requires": { + "@apollographql/graphql-language-service-types": "^2.0.0" + } + }, + "@apollographql/graphql-language-service-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-types/-/graphql-language-service-types-2.0.2.tgz", + "integrity": "sha512-vE+Dz8pG+Xa1Z2nMl82LoO66lQ6JqBUjaXqLDvS3eMjvA3N4hf+YUDOWfPdNZ0zjhHhHXzUIIZCkax6bXfFbzQ==", + "dev": true, + "requires": {} + }, + "@apollographql/graphql-language-service-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-utils/-/graphql-language-service-utils-2.0.2.tgz", + "integrity": "sha512-fDj5rWlTi/czvUS5t7V7I45Ai6bOO3Z7JARYj21Y2xxfbRGtJi6h8FvLX0N/EbzQgo/fiZc/HAhtfwn+OCjD7A==", + "dev": true, + "requires": { + "@apollographql/graphql-language-service-types": "^2.0.0" + } + }, "@babel/code-frame": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", @@ -30492,9 +30539,9 @@ "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=" }, "@mapbox/tiny-sdf": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.4.tgz", - "integrity": "sha512-CBtL2rhZiYmdIryksp0zh4Mmx54iClYfNb0mpYeHrZnq4z84lVjre7LBWGPEjWspEn6AiF0lxC1HaZDye89m3g==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.5.tgz", + "integrity": "sha512-OhXt2lS//WpLdkqrzo/KwB7SRD8AiNTFFzuo9n14IBupzIMa67yGItcK7I2W9D8Ghpa4T04Sw9FWsKCJG50Bxw==" }, "@mapbox/unitbezier": { "version": "0.0.0", @@ -31837,9 +31884,9 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "@types/node": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.13.tgz", - "integrity": "sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw==" + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.14.tgz", + "integrity": "sha512-SbjLmERksKOGzWzPNuW7fJM7fk3YXVTFiZWB/Hs99gwhk+/dnrQRPBQjPW9aO+fi1tAffi9PrwFvsmOKmDTyng==" }, "@types/node-fetch": { "version": "2.5.12", @@ -32544,7 +32591,7 @@ "git-url-parse": "11.5.0", "glob": "7.2.0", "global-agent": "2.2.0", - "graphql": "14.0.2 - 14.2.0 || ^14.3.1 || ^15.0.0", + "graphql": "^15.0.0", "graphql-tag": "2.12.4", "listr": "0.14.3", "lodash.identity": "3.0.0", @@ -32761,7 +32808,7 @@ "cosmiconfig": "^5.0.6", "dotenv": "^8.0.0", "glob": "^7.1.3", - "graphql": "14.0.2 - 14.2.0 || ^14.3.1 || ^15.0.0", + "graphql": "^15.0.0", "graphql-tag": "^2.10.1", "lodash.debounce": "^4.0.8", "lodash.merge": "^4.6.1", @@ -32771,42 +32818,6 @@ "vscode-uri": "1.0.6" }, "dependencies": { - "@apollographql/graphql-language-service-interface": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-interface/-/graphql-language-service-interface-2.0.2.tgz", - "integrity": "sha512-28wePK0hlIVjgmvMXMAUq8qRSjz9O+6lqFp4PzOTHtfJfSsjVe9EfjF98zTpHsTgT3HcOxmbqDZZy8jlXtOqEA==", - "dev": true, - "requires": { - "@apollographql/graphql-language-service-parser": "^2.0.0", - "@apollographql/graphql-language-service-types": "^2.0.0", - "@apollographql/graphql-language-service-utils": "^2.0.2" - } - }, - "@apollographql/graphql-language-service-parser": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-parser/-/graphql-language-service-parser-2.0.2.tgz", - "integrity": "sha512-rpTPrEJu1PMaRQxz5P8BZWsixNNhYloS0H0dwTxNBuE3qctbARvR7o8UCKLsmKgTbo+cz3T3a6IAsWlkHgMWGg==", - "dev": true, - "requires": { - "@apollographql/graphql-language-service-types": "^2.0.0" - } - }, - "@apollographql/graphql-language-service-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-types/-/graphql-language-service-types-2.0.2.tgz", - "integrity": "sha512-vE+Dz8pG+Xa1Z2nMl82LoO66lQ6JqBUjaXqLDvS3eMjvA3N4hf+YUDOWfPdNZ0zjhHhHXzUIIZCkax6bXfFbzQ==", - "dev": true, - "requires": {} - }, - "@apollographql/graphql-language-service-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-utils/-/graphql-language-service-utils-2.0.2.tgz", - "integrity": "sha512-fDj5rWlTi/czvUS5t7V7I45Ai6bOO3Z7JARYj21Y2xxfbRGtJi6h8FvLX0N/EbzQgo/fiZc/HAhtfwn+OCjD7A==", - "dev": true, - "requires": { - "@apollographql/graphql-language-service-types": "^2.0.0" - } - }, "@endemolshinegroup/cosmiconfig-typescript-loader": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.2.tgz", @@ -32837,15 +32848,6 @@ "parse-json": "^4.0.0" } }, - "graphql": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.7.0.tgz", - "integrity": "sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA==", - "dev": true, - "requires": { - "iterall": "^1.2.2" - } - }, "import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", @@ -33305,13 +33307,6 @@ "picocolors": "^0.2.1", "postcss": "^7.0.32", "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - } } }, "await-to-js": { @@ -33321,9 +33316,9 @@ "dev": true }, "axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.0.tgz", + "integrity": "sha512-btWy2rze3NnxSSxb7LtNhPYYFrRoFBfjiGzmSc/5Hu47wApO2KNXjP/w7Nv2Uz/Fyr/pfEiwOkcXhDxu0jz5FA==" }, "axobject-query": { "version": "2.2.0", @@ -33756,6 +33751,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "blurhash": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-1.1.4.tgz", + "integrity": "sha512-MXIPz6zwYUKayju+Uidf83KhH0vodZfeRl6Ich8Gu+KGl0JgKiFq9LsfqV7cVU5fKD/AotmduZqvOfrGKOfTaA==" + }, "bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", @@ -34004,6 +34004,13 @@ "escalade": "^3.1.1", "node-releases": "^2.0.1", "picocolors": "^1.0.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + } } }, "bser": { @@ -35053,14 +35060,14 @@ } }, "core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==" + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.0.tgz", + "integrity": "sha512-YUdI3fFu4TF/2WykQ2xzSiTQdldLB4KVuL9WeAy5XONZYt5Cun/fpQvctoKbCgvPhmzADeesTk/j2Rdx77AcKQ==" }, "core-js-compat": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.3.tgz", - "integrity": "sha512-c8M5h0IkNZ+I92QhIpuSijOxGAcj3lgpsWdkCqmUTZNwidujF4r3pi6x1DCN+Vcs5qTS2XWWMfWSuCqyupX8gw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "requires": { "browserslist": "^4.19.1", "semver": "7.0.0" @@ -35074,9 +35081,9 @@ } }, "core-js-pure": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.20.3.tgz", - "integrity": "sha512-Q2H6tQ5MtPtcC7f3HxJ48i4Q7T9ybPKgvWyuH7JXIoNa2pm0KuBnycsET/qw1SLLZYfbsbrZQNMeIOClb+6WIA==" + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.0.tgz", + "integrity": "sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==" }, "core-util-is": { "version": "1.0.3", @@ -36116,9 +36123,9 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron-to-chromium": { - "version": "1.4.57", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.57.tgz", - "integrity": "sha512-FNC+P5K1n6pF+M0zIK+gFCoXcJhhzDViL3DRIGy2Fv5PohuSES1JHR7T+GlwxSxlzx4yYbsuzCZvHxcBSRCIOw==" + "version": "1.4.60", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.60.tgz", + "integrity": "sha512-h53hbEiKC6hijelDgxgkgAUC3PKyR7TmIfvjHnBjUGPMg/3sBuTyG6eDormw+lY24uUJvHkUPzB8dpK8b2u3Sw==" }, "elegant-spinner": { "version": "1.0.1", @@ -41462,9 +41469,9 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "lint-staged": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.2.tgz", - "integrity": "sha512-gtw4Cbj01SuVSfAOXC6ivd/7VKHTj51yj5xV8TgktFmYNMsZzXuSd5/brqJEA93v63wL7R6iDlunMANOechC0A==", + "version": "12.3.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.3.tgz", + "integrity": "sha512-OqcLsqcPOqzvsfkxjeBpZylgJ3SRG1RYqc9LxC6tkt6tNsq1bNVkAixBwX09f6CobcHswzqVOCBpFR1Fck0+ag==", "dev": true, "requires": { "cli-truncate": "^3.1.0", @@ -41645,9 +41652,9 @@ } }, "listr2": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.1.tgz", - "integrity": "sha512-D65Nl+zyYHL2jQBGmxtH/pU8koPZo5C8iCNE8EoB04RwPgQG1wuaKwVbeZv9LJpiH4Nxs0FCp+nNcG8OqpniiA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.2.tgz", + "integrity": "sha512-YcgwfCWpvPbj9FLUGqvdFvd3hrFWKpOeuXznRgfWEJ7RNr8b/IKKIKZABHx3aU+4CWN/iSAFFSReziQG6vTeIA==", "dev": true, "requires": { "cli-truncate": "^2.1.0", @@ -42132,9 +42139,9 @@ } }, "mapbox-gl": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.6.1.tgz", - "integrity": "sha512-faGbSZfcFuZ4GWwkWnJrRD3oICZAt/mVKnGuOmeBobCj9onfTRz270qSoOXeRBKd3po5VA2cCPI91YwA8DsAoQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.7.0.tgz", + "integrity": "sha512-7sNoQIpizMjoQkFIcxpWzFCcMd8GJFN0Po00oFZGm1X7xS5XMrzwu+ClfO/ehZqKLa9IS7E3Pj0e2PT+9KeqaA==", "requires": { "@mapbox/geojson-rewind": "^0.5.1", "@mapbox/geojson-types": "^1.0.2", @@ -43531,9 +43538,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "picomatch": { "version": "2.3.1", @@ -43693,11 +43700,6 @@ "source-map": "^0.6.1" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -44638,14 +44640,19 @@ "postcss": "^8.1.0" }, "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "requires": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" } } } @@ -44920,14 +44927,19 @@ "postcss-selector-parser": "^6.0.6" }, "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "requires": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" } } } @@ -45080,6 +45092,12 @@ "whatwg-fetch": "^3.4.1" } }, + "react-blurhash": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/react-blurhash/-/react-blurhash-0.1.3.tgz", + "integrity": "sha512-Q9lqbXg92NU6/2DoIl/cBM8YWL+Z4X66OiG4aT9ozOgjBwx104LHFCH5stf6aF+s0Q9Wf310Ul+dG+VXJltmPg==", + "requires": {} + }, "react-dev-utils": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", diff --git a/ui/package.json b/ui/package.json index 89adb4d..5cf8801 100644 --- a/ui/package.json +++ b/ui/package.json @@ -26,6 +26,7 @@ "@types/url-join": "^4.0.1", "autoprefixer": "^9.8.6", "babel-plugin-graphql-tag": "^3.3.0", + "blurhash": "^1.1.4", "classnames": "^2.3.1", "connect-history-api-fallback": "^1.6.0", "copy-to-clipboard": "^3.3.1", @@ -38,6 +39,7 @@ "prettier": "^2.5.1", "prop-types": "^15.8.1", "react": "^17.0.2", + "react-blurhash": "^0.1.3", "react-dom": "^17.0.2", "react-helmet": "^6.1.0", "react-hook-form": "^7.25.3", @@ -79,6 +81,9 @@ "lint-staged": "^12.3.2", "tsc-files": "1.1.2" }, + "overrides": { + "graphql": "^15.0.0" + }, "prettier": { "trailingComma": "es5", "tabWidth": 2, diff --git a/ui/src/Pages/AlbumPage/AlbumPage.tsx b/ui/src/Pages/AlbumPage/AlbumPage.tsx index d8e02a2..4b85936 100644 --- a/ui/src/Pages/AlbumPage/AlbumPage.tsx +++ b/ui/src/Pages/AlbumPage/AlbumPage.tsx @@ -43,6 +43,7 @@ const ALBUM_QUERY = gql` ) { id type + blurhash thumbnail { url width diff --git a/ui/src/Pages/AlbumPage/__generated__/albumQuery.ts b/ui/src/Pages/AlbumPage/__generated__/albumQuery.ts index f7138d2..f81f35a 100644 --- a/ui/src/Pages/AlbumPage/__generated__/albumQuery.ts +++ b/ui/src/Pages/AlbumPage/__generated__/albumQuery.ts @@ -3,102 +3,106 @@ // @generated // This file was automatically generated and should not be edited. -import { OrderDirection, MediaType } from "./../../../__generated__/globalTypes"; +import { OrderDirection, MediaType } from './../../../__generated__/globalTypes' // ==================================================== // GraphQL query operation: albumQuery // ==================================================== export interface albumQuery_album_subAlbums_thumbnail_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string } export interface albumQuery_album_subAlbums_thumbnail { - __typename: "Media"; - id: string; + __typename: 'Media' + id: string /** * URL to display the media in a smaller resolution */ - thumbnail: albumQuery_album_subAlbums_thumbnail_thumbnail | null; + thumbnail: albumQuery_album_subAlbums_thumbnail_thumbnail | null } export interface albumQuery_album_subAlbums { - __typename: "Album"; - id: string; - title: string; + __typename: 'Album' + id: string + title: string /** * An image in this album used for previewing this album */ - thumbnail: albumQuery_album_subAlbums_thumbnail | null; + thumbnail: albumQuery_album_subAlbums_thumbnail | null } export interface albumQuery_album_media_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface albumQuery_album_media_highRes { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string } export interface albumQuery_album_media_videoWeb { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string } export interface albumQuery_album_media { - __typename: "Media"; - id: string; - type: MediaType; + __typename: 'Media' + id: string + type: MediaType + /** + * A short string that can be used to generate a blured version of the media, to show while the original is loading + */ + blurhash: string | null /** * URL to display the media in a smaller resolution */ - thumbnail: albumQuery_album_media_thumbnail | null; + thumbnail: albumQuery_album_media_thumbnail | null /** * URL to display the photo in full resolution, will be null for videos */ - highRes: albumQuery_album_media_highRes | null; + highRes: albumQuery_album_media_highRes | null /** * URL to get the video in a web format that can be played in the browser, will be null for photos */ - videoWeb: albumQuery_album_media_videoWeb | null; - favorite: boolean; + videoWeb: albumQuery_album_media_videoWeb | null + favorite: boolean } export interface albumQuery_album { - __typename: "Album"; - id: string; - title: string; + __typename: 'Album' + id: string + title: string /** * The albums contained in this album */ - subAlbums: albumQuery_album_subAlbums[]; + subAlbums: albumQuery_album_subAlbums[] /** * The media inside this album */ - media: albumQuery_album_media[]; + media: albumQuery_album_media[] } export interface albumQuery { @@ -106,14 +110,14 @@ export interface albumQuery { * Get album by id, user must own the album or be admin * If valid tokenCredentials are provided, the album may be retrived without further authentication */ - album: albumQuery_album; + album: albumQuery_album } export interface albumQueryVariables { - id: string; - onlyFavorites?: boolean | null; - mediaOrderBy?: string | null; - mediaOrderDirection?: OrderDirection | null; - limit?: number | null; - offset?: number | null; + id: string + onlyFavorites?: boolean | null + mediaOrderBy?: string | null + mediaOrderDirection?: OrderDirection | null + limit?: number | null + offset?: number | null } diff --git a/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.tsx b/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.tsx index 7327040..51c23d7 100644 --- a/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.tsx +++ b/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.tsx @@ -28,6 +28,7 @@ export const SINGLE_FACE_GROUP = gql` id type title + blurhash thumbnail { url width diff --git a/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts b/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts index b5d773c..788e7a2 100644 --- a/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts +++ b/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts @@ -3,80 +3,84 @@ // @generated // This file was automatically generated and should not be edited. -import { MediaType } from "./../../../../__generated__/globalTypes"; +import { MediaType } from './../../../../__generated__/globalTypes' // ==================================================== // GraphQL query operation: singleFaceGroup // ==================================================== export interface singleFaceGroup_faceGroup_imageFaces_rectangle { - __typename: "FaceRectangle"; - minX: number; - maxX: number; - minY: number; - maxY: number; + __typename: 'FaceRectangle' + minX: number + maxX: number + minY: number + maxY: number } export interface singleFaceGroup_faceGroup_imageFaces_media_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface singleFaceGroup_faceGroup_imageFaces_media_highRes { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string } export interface singleFaceGroup_faceGroup_imageFaces_media { - __typename: "Media"; - id: string; - type: MediaType; - title: string; + __typename: 'Media' + id: string + type: MediaType + title: string + /** + * A short string that can be used to generate a blured version of the media, to show while the original is loading + */ + blurhash: string | null /** * URL to display the media in a smaller resolution */ - thumbnail: singleFaceGroup_faceGroup_imageFaces_media_thumbnail | null; + thumbnail: singleFaceGroup_faceGroup_imageFaces_media_thumbnail | null /** * URL to display the photo in full resolution, will be null for videos */ - highRes: singleFaceGroup_faceGroup_imageFaces_media_highRes | null; - favorite: boolean; + highRes: singleFaceGroup_faceGroup_imageFaces_media_highRes | null + favorite: boolean } export interface singleFaceGroup_faceGroup_imageFaces { - __typename: "ImageFace"; - id: string; - rectangle: singleFaceGroup_faceGroup_imageFaces_rectangle; - media: singleFaceGroup_faceGroup_imageFaces_media; + __typename: 'ImageFace' + id: string + rectangle: singleFaceGroup_faceGroup_imageFaces_rectangle + media: singleFaceGroup_faceGroup_imageFaces_media } export interface singleFaceGroup_faceGroup { - __typename: "FaceGroup"; - id: string; - label: string | null; - imageFaces: singleFaceGroup_faceGroup_imageFaces[]; + __typename: 'FaceGroup' + id: string + label: string | null + imageFaces: singleFaceGroup_faceGroup_imageFaces[] } export interface singleFaceGroup { - faceGroup: singleFaceGroup_faceGroup; + faceGroup: singleFaceGroup_faceGroup } export interface singleFaceGroupVariables { - id: string; - limit: number; - offset: number; + id: string + limit: number + offset: number } diff --git a/ui/src/Pages/PlacesPage/MapPresentMarker.tsx b/ui/src/Pages/PlacesPage/MapPresentMarker.tsx index c4b4be4..ce1a89a 100644 --- a/ui/src/Pages/PlacesPage/MapPresentMarker.tsx +++ b/ui/src/Pages/PlacesPage/MapPresentMarker.tsx @@ -15,6 +15,7 @@ const QUERY_MEDIA = gql` mediaList(ids: $mediaIDs) { id title + blurhash thumbnail { url width diff --git a/ui/src/Pages/PlacesPage/__generated__/placePageMapboxToken.ts b/ui/src/Pages/PlacesPage/__generated__/placePageMapboxToken.ts index e519734..a88c85e 100644 --- a/ui/src/Pages/PlacesPage/__generated__/placePageMapboxToken.ts +++ b/ui/src/Pages/PlacesPage/__generated__/placePageMapboxToken.ts @@ -11,9 +11,9 @@ export interface placePageMapboxToken { /** * Get the mapbox api token, returns null if mapbox is not enabled */ - mapboxToken: string | null; + mapboxToken: string | null /** * Get media owned by the logged in user, returned in GeoJson format */ - myMediaGeoJson: any; + myMediaGeoJson: any } diff --git a/ui/src/Pages/PlacesPage/__generated__/placePageQueryMedia.ts b/ui/src/Pages/PlacesPage/__generated__/placePageQueryMedia.ts index 056bd39..ddae3ac 100644 --- a/ui/src/Pages/PlacesPage/__generated__/placePageQueryMedia.ts +++ b/ui/src/Pages/PlacesPage/__generated__/placePageQueryMedia.ts @@ -3,86 +3,90 @@ // @generated // This file was automatically generated and should not be edited. -import { MediaType } from "./../../../__generated__/globalTypes"; +import { MediaType } from './../../../__generated__/globalTypes' // ==================================================== // GraphQL query operation: placePageQueryMedia // ==================================================== export interface placePageQueryMedia_mediaList_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface placePageQueryMedia_mediaList_highRes { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface placePageQueryMedia_mediaList_videoWeb { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface placePageQueryMedia_mediaList { - __typename: "Media"; - id: string; - title: string; + __typename: 'Media' + id: string + title: string + /** + * A short string that can be used to generate a blured version of the media, to show while the original is loading + */ + blurhash: string | null /** * URL to display the media in a smaller resolution */ - thumbnail: placePageQueryMedia_mediaList_thumbnail | null; + thumbnail: placePageQueryMedia_mediaList_thumbnail | null /** * URL to display the photo in full resolution, will be null for videos */ - highRes: placePageQueryMedia_mediaList_highRes | null; + highRes: placePageQueryMedia_mediaList_highRes | null /** * URL to get the video in a web format that can be played in the browser, will be null for photos */ - videoWeb: placePageQueryMedia_mediaList_videoWeb | null; - type: MediaType; + videoWeb: placePageQueryMedia_mediaList_videoWeb | null + type: MediaType } export interface placePageQueryMedia { /** * Get a list of media by their ids, user must own the media or be admin */ - mediaList: placePageQueryMedia_mediaList[]; + mediaList: placePageQueryMedia_mediaList[] } export interface placePageQueryMediaVariables { - mediaIDs: string[]; + mediaIDs: string[] } diff --git a/ui/src/Pages/SharePage/AlbumSharePage.tsx b/ui/src/Pages/SharePage/AlbumSharePage.tsx index 6635d12..063a5a3 100644 --- a/ui/src/Pages/SharePage/AlbumSharePage.tsx +++ b/ui/src/Pages/SharePage/AlbumSharePage.tsx @@ -43,6 +43,7 @@ export const SHARE_ALBUM_QUERY = gql` id title type + blurhash thumbnail { url width diff --git a/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts b/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts index f65bdaa..21487e3 100644 --- a/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts +++ b/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts @@ -3,179 +3,200 @@ // @generated // This file was automatically generated and should not be edited. -import { OrderDirection, MediaType } from "./../../../__generated__/globalTypes"; +import { OrderDirection, MediaType } from './../../../__generated__/globalTypes' // ==================================================== // GraphQL query operation: shareAlbumQuery // ==================================================== export interface shareAlbumQuery_album_subAlbums_thumbnail_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string } export interface shareAlbumQuery_album_subAlbums_thumbnail { - __typename: "Media"; - id: string; + __typename: 'Media' + id: string /** * URL to display the media in a smaller resolution */ - thumbnail: shareAlbumQuery_album_subAlbums_thumbnail_thumbnail | null; + thumbnail: shareAlbumQuery_album_subAlbums_thumbnail_thumbnail | null } export interface shareAlbumQuery_album_subAlbums { - __typename: "Album"; - id: string; - title: string; + __typename: 'Album' + id: string + title: string /** * An image in this album used for previewing this album */ - thumbnail: shareAlbumQuery_album_subAlbums_thumbnail | null; + thumbnail: shareAlbumQuery_album_subAlbums_thumbnail | null } export interface shareAlbumQuery_album_media_thumbnail { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface shareAlbumQuery_album_media_downloads_mediaUrl { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number /** * The file size of the resource in bytes */ - fileSize: number; + fileSize: number } export interface shareAlbumQuery_album_media_downloads { - __typename: "MediaDownload"; - title: string; - mediaUrl: shareAlbumQuery_album_media_downloads_mediaUrl; + __typename: 'MediaDownload' + title: string + mediaUrl: shareAlbumQuery_album_media_downloads_mediaUrl } export interface shareAlbumQuery_album_media_highRes { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string /** * Width of the image in pixels */ - width: number; + width: number /** * Height of the image in pixels */ - height: number; + height: number } export interface shareAlbumQuery_album_media_videoWeb { - __typename: "MediaURL"; + __typename: 'MediaURL' /** * URL for previewing the image */ - url: string; + url: string +} + +export interface shareAlbumQuery_album_media_exif_coordinates { + __typename: 'Coordinates' + /** + * GPS latitude in degrees + */ + latitude: number + /** + * GPS longitude in degrees + */ + longitude: number } export interface shareAlbumQuery_album_media_exif { - __typename: "MediaEXIF"; + __typename: 'MediaEXIF' + id: string /** * The model name of the camera */ - camera: string | null; + camera: string | null /** * The maker of the camera */ - maker: string | null; + maker: string | null /** * The name of the lens */ - lens: string | null; - dateShot: any | null; + lens: string | null + dateShot: any | null /** * The exposure time of the image */ - exposure: number | null; + exposure: number | null /** * The aperature stops of the image */ - aperture: number | null; + aperture: number | null /** * The ISO setting of the image */ - iso: number | null; + iso: number | null /** * The focal length of the lens, when the image was taken */ - focalLength: number | null; + focalLength: number | null /** * A formatted description of the flash settings, when the image was taken */ - flash: number | null; + flash: number | null /** * An index describing the mode for adjusting the exposure of the image */ - exposureProgram: number | null; + exposureProgram: number | null + /** + * GPS coordinates of where the image was taken + */ + coordinates: shareAlbumQuery_album_media_exif_coordinates | null } export interface shareAlbumQuery_album_media { - __typename: "Media"; - id: string; - title: string; - type: MediaType; + __typename: 'Media' + id: string + title: string + type: MediaType + /** + * A short string that can be used to generate a blured version of the media, to show while the original is loading + */ + blurhash: string | null /** * URL to display the media in a smaller resolution */ - thumbnail: shareAlbumQuery_album_media_thumbnail | null; - downloads: shareAlbumQuery_album_media_downloads[]; + thumbnail: shareAlbumQuery_album_media_thumbnail | null + downloads: shareAlbumQuery_album_media_downloads[] /** * URL to display the photo in full resolution, will be null for videos */ - highRes: shareAlbumQuery_album_media_highRes | null; + highRes: shareAlbumQuery_album_media_highRes | null /** * URL to get the video in a web format that can be played in the browser, will be null for photos */ - videoWeb: shareAlbumQuery_album_media_videoWeb | null; - exif: shareAlbumQuery_album_media_exif | null; + videoWeb: shareAlbumQuery_album_media_videoWeb | null + exif: shareAlbumQuery_album_media_exif | null } export interface shareAlbumQuery_album { - __typename: "Album"; - id: string; - title: string; + __typename: 'Album' + id: string + title: string /** * The albums contained in this album */ - subAlbums: shareAlbumQuery_album_subAlbums[]; + subAlbums: shareAlbumQuery_album_subAlbums[] /** * The media inside this album */ - media: shareAlbumQuery_album_media[]; + media: shareAlbumQuery_album_media[] } export interface shareAlbumQuery { @@ -183,15 +204,15 @@ export interface shareAlbumQuery { * Get album by id, user must own the album or be admin * If valid tokenCredentials are provided, the album may be retrived without further authentication */ - album: shareAlbumQuery_album; + album: shareAlbumQuery_album } export interface shareAlbumQueryVariables { - id: string; - token: string; - password?: string | null; - mediaOrderBy?: string | null; - mediaOrderDirection?: OrderDirection | null; - limit?: number | null; - offset?: number | null; + id: string + token: string + password?: string | null + mediaOrderBy?: string | null + mediaOrderDirection?: OrderDirection | null + limit?: number | null + offset?: number | null } diff --git a/ui/src/__generated__/adminQuery.ts b/ui/src/__generated__/adminQuery.ts index 232a958..2301f23 100644 --- a/ui/src/__generated__/adminQuery.ts +++ b/ui/src/__generated__/adminQuery.ts @@ -8,13 +8,13 @@ // ==================================================== export interface adminQuery_myUser { - __typename: "User"; - admin: boolean; + __typename: 'User' + admin: boolean } export interface adminQuery { /** * Information about the currently logged in user */ - myUser: adminQuery_myUser; + myUser: adminQuery_myUser } diff --git a/ui/src/__generated__/mapboxEnabledQuery.ts b/ui/src/__generated__/mapboxEnabledQuery.ts index e666de4..0600784 100644 --- a/ui/src/__generated__/mapboxEnabledQuery.ts +++ b/ui/src/__generated__/mapboxEnabledQuery.ts @@ -11,5 +11,5 @@ export interface mapboxEnabledQuery { /** * Get the mapbox api token, returns null if mapbox is not enabled */ - mapboxToken: string | null; + mapboxToken: string | null } diff --git a/ui/src/components/albumGallery/AlbumGallery.tsx b/ui/src/components/albumGallery/AlbumGallery.tsx index 09390bc..f640f40 100644 --- a/ui/src/components/albumGallery/AlbumGallery.tsx +++ b/ui/src/components/albumGallery/AlbumGallery.tsx @@ -38,6 +38,7 @@ type AlbumGalleryAlbum = { */ videoWeb: albumQuery_album_media_videoWeb | null favorite?: boolean + blurhash: string | null }[] } diff --git a/ui/src/components/photoGallery/MediaThumbnail.tsx b/ui/src/components/photoGallery/MediaThumbnail.tsx index e9df158..9a6fb9c 100644 --- a/ui/src/components/photoGallery/MediaThumbnail.tsx +++ b/ui/src/components/photoGallery/MediaThumbnail.tsx @@ -25,6 +25,7 @@ const StyledPhoto = styled(ProtectedImage)` type LazyPhotoProps = { src?: string + blurhash: string | null } const LazyPhoto = (photoProps: LazyPhotoProps) => { @@ -138,6 +139,7 @@ type MediaThumbnailProps = { media: { id: string type: MediaType + blurhash: string | null favorite?: boolean thumbnail: null | { url: string @@ -201,7 +203,7 @@ export const MediaThumbnail = ({ height: `200px`, }} > - + {videoIcon} diff --git a/ui/src/components/photoGallery/PhotoGallery.test.tsx b/ui/src/components/photoGallery/PhotoGallery.test.tsx index 8fe4aa0..082bcfd 100644 --- a/ui/src/components/photoGallery/PhotoGallery.test.tsx +++ b/ui/src/components/photoGallery/PhotoGallery.test.tsx @@ -26,6 +26,7 @@ test('photo gallery with media', () => { }, highRes: null, videoWeb: null, + blurhash: null, favorite: false, __typename: 'Media', }, @@ -35,6 +36,7 @@ test('photo gallery with media', () => { thumbnail: null, highRes: null, videoWeb: null, + blurhash: null, favorite: false, __typename: 'Media', }, @@ -44,6 +46,7 @@ test('photo gallery with media', () => { thumbnail: null, highRes: null, videoWeb: null, + blurhash: null, favorite: false, __typename: 'Media', }, @@ -100,6 +103,7 @@ describe('photo gallery presenting', () => { }, highRes: null, videoWeb: null, + blurhash: null, favorite: false, __typename: 'Media', }, diff --git a/ui/src/components/photoGallery/PhotoGallery.tsx b/ui/src/components/photoGallery/PhotoGallery.tsx index 3521f71..d781ec5 100644 --- a/ui/src/components/photoGallery/PhotoGallery.tsx +++ b/ui/src/components/photoGallery/PhotoGallery.tsx @@ -37,6 +37,7 @@ export const PhotoFiller = styled.div` export interface PhotoGalleryProps_Media extends PresentMediaProps_Media { thumbnail: sidebarMediaQuery_media_thumbnail | null + blurhash: string | null favorite?: boolean } diff --git a/ui/src/components/photoGallery/ProtectedMedia.tsx b/ui/src/components/photoGallery/ProtectedMedia.tsx index e77da32..305f16d 100644 --- a/ui/src/components/photoGallery/ProtectedMedia.tsx +++ b/ui/src/components/photoGallery/ProtectedMedia.tsx @@ -3,6 +3,7 @@ import React, { DetailedHTMLProps, ImgHTMLAttributes } from 'react' import { useRef } from 'react' import { useState } from 'react' import { useEffect } from 'react' +import { BlurhashCanvas } from 'react-blurhash' import { isNil } from '../../helpers/utils' const isNativeLazyLoadSupported = 'loading' in document.createElement('img') @@ -31,6 +32,7 @@ export interface ProtectedImageProps src?: string key?: string lazyLoading?: boolean + blurhash?: string | null } /** @@ -42,10 +44,15 @@ export interface ProtectedImageProps export const ProtectedImage = ({ src, lazyLoading, + blurhash, ...props }: ProtectedImageProps) => { + const [loaded, setLoaded] = useState(false) + const url = getProtectedUrl(src) || placeholder + const didLoad = () => setLoaded(true) + if (!lazyLoading) { return ( @@ -53,12 +60,26 @@ export const ProtectedImage = ({ } if (!isNativeLazyLoadSupported) { - return + return } // load with native lazy loading return ( - +
+ + {blurhash && !loaded && ( + + )} +
) } @@ -68,15 +89,22 @@ interface FallbackLazyloadedImageProps 'src' > { src?: string + blurhash?: string | null } const FallbackLazyloadedImage = ({ src, + blurhash, + className, ...props }: FallbackLazyloadedImageProps) => { const [inView, setInView] = useState(false) + const [loaded, setLoaded] = useState(false) + const imgRef = useRef(null) + const didLoad = () => setLoaded(true) + useEffect(() => { const imgElm = imgRef.current if (isNil(imgElm) || inView) return @@ -107,13 +135,33 @@ const FallbackLazyloadedImage = ({ }, [imgRef]) if (inView) { - return + return ( +
+ + {blurhash && !loaded && ( + + )} +
+ ) } else { return ( -
+
+ {blurhash && ( + + )} +
) } } diff --git a/ui/src/components/photoGallery/photoGalleryReducer.test.ts b/ui/src/components/photoGallery/photoGalleryReducer.test.ts index d7c7a40..73a0c1f 100644 --- a/ui/src/components/photoGallery/photoGalleryReducer.test.ts +++ b/ui/src/components/photoGallery/photoGalleryReducer.test.ts @@ -11,6 +11,7 @@ describe('photo gallery reducer', () => { id: '1', highRes: null, thumbnail: null, + blurhash: null, type: MediaType.Photo, }, { @@ -18,6 +19,7 @@ describe('photo gallery reducer', () => { id: '2', highRes: null, thumbnail: null, + blurhash: null, type: MediaType.Photo, }, { @@ -25,6 +27,7 @@ describe('photo gallery reducer', () => { id: '3', highRes: null, thumbnail: null, + blurhash: null, type: MediaType.Photo, }, ], diff --git a/ui/src/components/timelineGallery/TimelineGallery.test.tsx b/ui/src/components/timelineGallery/TimelineGallery.test.tsx index ed99760..2045929 100644 --- a/ui/src/components/timelineGallery/TimelineGallery.test.tsx +++ b/ui/src/components/timelineGallery/TimelineGallery.test.tsx @@ -34,6 +34,4 @@ test('timeline with media', async () => { expect(await screen.findAllByRole('link')).toHaveLength(4) expect(await screen.findAllByRole('img')).toHaveLength(5) - - screen.debug() }) diff --git a/ui/src/components/timelineGallery/TimelineGallery.tsx b/ui/src/components/timelineGallery/TimelineGallery.tsx index 8d0c793..cc11354 100644 --- a/ui/src/components/timelineGallery/TimelineGallery.tsx +++ b/ui/src/components/timelineGallery/TimelineGallery.tsx @@ -35,6 +35,7 @@ export const MY_TIMELINE_QUERY = gql` id title type + blurhash thumbnail { url width diff --git a/ui/src/components/timelineGallery/__generated__/myTimeline.ts b/ui/src/components/timelineGallery/__generated__/myTimeline.ts index faa63f4..118b42e 100644 --- a/ui/src/components/timelineGallery/__generated__/myTimeline.ts +++ b/ui/src/components/timelineGallery/__generated__/myTimeline.ts @@ -60,6 +60,10 @@ export interface myTimeline_myTimeline { id: string title: string type: MediaType + /** + * A short string that can be used to generate a blured version of the media, to show while the original is loading + */ + blurhash: string | null /** * URL to display the media in a smaller resolution */ diff --git a/ui/src/components/timelineGallery/timelineTestData.ts b/ui/src/components/timelineGallery/timelineTestData.ts index 5d11890..2163220 100644 --- a/ui/src/components/timelineGallery/timelineTestData.ts +++ b/ui/src/components/timelineGallery/timelineTestData.ts @@ -23,6 +23,7 @@ export const timelineData: myTimeline_myTimeline[] = [ favorite: false, album: { __typename: 'Album', id: '522', title: 'random' }, date: '2020-12-13T18:03:40Z', + blurhash: null, }, { __typename: 'Media', @@ -45,6 +46,7 @@ export const timelineData: myTimeline_myTimeline[] = [ favorite: false, album: { __typename: 'Album', id: '523', title: 'another_album' }, date: '2020-11-25T16:14:33Z', + blurhash: null, }, { __typename: 'Media', @@ -67,6 +69,7 @@ export const timelineData: myTimeline_myTimeline[] = [ favorite: false, album: { __typename: 'Album', id: '523', title: 'another_album' }, date: '2020-11-25T16:43:59Z', + blurhash: null, }, { __typename: 'Media', @@ -89,6 +92,7 @@ export const timelineData: myTimeline_myTimeline[] = [ favorite: false, album: { __typename: 'Album', id: '522', title: 'random' }, date: '2020-11-25T16:14:33Z', + blurhash: null, }, { __typename: 'Media', @@ -111,5 +115,6 @@ export const timelineData: myTimeline_myTimeline[] = [ favorite: false, album: { __typename: 'Album', id: '522', title: 'random' }, date: '2020-11-09T15:38:09Z', + blurhash: null, }, ] From b49333ae6910022e942792e57063546505e8a09a Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Wed, 2 Feb 2022 00:03:31 +0100 Subject: [PATCH 3/3] Add Media.GetThumbnail() tests --- api/graphql/models/media_test.go | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/api/graphql/models/media_test.go b/api/graphql/models/media_test.go index ae2f16b..48a453d 100644 --- a/api/graphql/models/media_test.go +++ b/api/graphql/models/media_test.go @@ -67,3 +67,56 @@ func TestMediaURLGetURL(t *testing.T) { assert.Equal(t, "video/video.mp4", video.URL()) } + +func TestMediaGetThumbnail(t *testing.T) { + photo := models.Media{ + Title: "test.png", + Path: "path/test.png", + Type: models.MediaTypePhoto, + MediaURL: []models.MediaURL{ + { + MediaName: "photo.jpg", + ContentType: "image/jpeg", + Purpose: models.PhotoHighRes, + }, + { + MediaName: "thumbnail.jpg", + ContentType: "image/jpeg", + Purpose: models.PhotoThumbnail, + }, + { + MediaName: "photo.png", + ContentType: "image/png", + Purpose: models.MediaOriginal, + }, + }, + } + + thumb, err := photo.GetThumbnail() + assert.NoError(t, err) + assert.Equal(t, thumb.MediaName, "thumbnail.jpg") + assert.NotNil(t, thumb.Media) + + video := models.Media{ + Title: "video-test.mp4", + Path: "path/test.mp4", + Type: models.MediaTypePhoto, + MediaURL: []models.MediaURL{ + { + MediaName: "video.mp4", + ContentType: "video/mp4", + Purpose: models.VideoWeb, + }, + { + MediaName: "video-thumbnail.jpg", + ContentType: "image/jpg", + Purpose: models.VideoThumbnail, + }, + }, + } + + thumb, err = video.GetThumbnail() + assert.NoError(t, err) + assert.Equal(t, thumb.MediaName, "video-thumbnail.jpg") + assert.NotNil(t, thumb.Media) +}