Merge branch 'master' into improved-timeline
This commit is contained in:
commit
612a191f6d
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
|
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep --silent '.go$')
|
||||||
[ -z "$gofiles" ] && exit 0
|
[ -z "$gofiles" ] && exit 0
|
||||||
|
|
||||||
# Automatically format go code, exit on error
|
# Automatically format go code, exit on error
|
||||||
|
|
|
@ -28,6 +28,7 @@ Password: **demo**
|
||||||
|
|
||||||
- [Demo site](#demo-site)
|
- [Demo site](#demo-site)
|
||||||
- [Main features](#main-features)
|
- [Main features](#main-features)
|
||||||
|
- [Supported Platforms](#supported-platforms)
|
||||||
- [Why yet another self-hosted photo gallery](#why-yet-another-self-hosted-photo-gallery)
|
- [Why yet another self-hosted photo gallery](#why-yet-another-self-hosted-photo-gallery)
|
||||||
- [Getting started - Setup with Docker](#getting-started---setup-with-docker)
|
- [Getting started - Setup with Docker](#getting-started---setup-with-docker)
|
||||||
- [Set up development environment](#setup-development-environment)
|
- [Set up development environment](#setup-development-environment)
|
||||||
|
@ -44,6 +45,14 @@ Password: **demo**
|
||||||
- **Performant**. Thumbnails are automatically generated and photos first load when they are visible on the screen. In full screen, thumbnails are displayed until the high resolution image has been fully loaded.
|
- **Performant**. Thumbnails are automatically generated and photos first load when they are visible on the screen. In full screen, thumbnails are displayed until the high resolution image has been fully loaded.
|
||||||
- **Secure**. All media resources are protected with a cookie-token, all passwords are properly hashed, and the API uses a strict [CORS policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
|
- **Secure**. All media resources are protected with a cookie-token, all passwords are properly hashed, and the API uses a strict [CORS policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
|
|
||||||
|
- [Docker](https://hub.docker.com/r/viktorstrate/photoview/)
|
||||||
|
- [Arch Linux Aur](https://aur.archlinux.org/packages/photoview)
|
||||||
|
- [Unraid](https://forums.unraid.net/topic/103028-support-photoview-corneliousjd-repo/)
|
||||||
|
- EmbassyOS: [announcement](https://start9labs.medium.com/new-service-photoview-72ee681b2ff0), [repo](https://github.com/Start9Labs/embassyos-photoview-wrapper)
|
||||||
|
- [YunoHost](https://github.com/YunoHost-Apps/photoview_ynh)
|
||||||
|
|
||||||
## Why yet another self-hosted photo gallery
|
## Why yet another self-hosted photo gallery
|
||||||
|
|
||||||
There exists a lot of open-source self-hosted photo galleries already. Here are some, just to mention a few.
|
There exists a lot of open-source self-hosted photo galleries already. Here are some, just to mention a few.
|
||||||
|
|
|
@ -154,8 +154,10 @@ type ComplexityRoot struct {
|
||||||
MoveImageFaces func(childComplexity int, imageFaceIDs []int, destinationFaceGroupID int) int
|
MoveImageFaces func(childComplexity int, imageFaceIDs []int, destinationFaceGroupID int) int
|
||||||
ProtectShareToken func(childComplexity int, token string, password *string) int
|
ProtectShareToken func(childComplexity int, token string, password *string) int
|
||||||
RecognizeUnlabeledFaces func(childComplexity int) int
|
RecognizeUnlabeledFaces func(childComplexity int) int
|
||||||
|
ResetAlbumCover func(childComplexity int, albumID int) int
|
||||||
ScanAll func(childComplexity int) int
|
ScanAll func(childComplexity int) int
|
||||||
ScanUser func(childComplexity int, userID int) int
|
ScanUser func(childComplexity int, userID int) int
|
||||||
|
SetAlbumCover func(childComplexity int, coverID int) int
|
||||||
SetFaceGroupLabel func(childComplexity int, faceGroupID int, label *string) int
|
SetFaceGroupLabel func(childComplexity int, faceGroupID int, label *string) int
|
||||||
SetPeriodicScanInterval func(childComplexity int, interval int) int
|
SetPeriodicScanInterval func(childComplexity int, interval int) int
|
||||||
SetScannerConcurrentWorkers func(childComplexity int, workers int) int
|
SetScannerConcurrentWorkers func(childComplexity int, workers int) int
|
||||||
|
@ -314,6 +316,8 @@ type MutationResolver interface {
|
||||||
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
|
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
|
||||||
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
|
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
|
||||||
ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error)
|
ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error)
|
||||||
|
ResetAlbumCover(ctx context.Context, albumID int) (*models.Album, error)
|
||||||
|
SetAlbumCover(ctx context.Context, coverID int) (*models.Album, error)
|
||||||
SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error)
|
SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error)
|
||||||
CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error)
|
CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error)
|
||||||
MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error)
|
MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error)
|
||||||
|
@ -928,6 +932,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.RecognizeUnlabeledFaces(childComplexity), true
|
return e.complexity.Mutation.RecognizeUnlabeledFaces(childComplexity), true
|
||||||
|
|
||||||
|
case "Mutation.resetAlbumCover":
|
||||||
|
if e.complexity.Mutation.ResetAlbumCover == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_resetAlbumCover_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.ResetAlbumCover(childComplexity, args["albumID"].(int)), true
|
||||||
|
|
||||||
case "Mutation.scanAll":
|
case "Mutation.scanAll":
|
||||||
if e.complexity.Mutation.ScanAll == nil {
|
if e.complexity.Mutation.ScanAll == nil {
|
||||||
break
|
break
|
||||||
|
@ -947,6 +963,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.ScanUser(childComplexity, args["userId"].(int)), true
|
return e.complexity.Mutation.ScanUser(childComplexity, args["userId"].(int)), true
|
||||||
|
|
||||||
|
case "Mutation.setAlbumCover":
|
||||||
|
if e.complexity.Mutation.SetAlbumCover == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_setAlbumCover_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.SetAlbumCover(childComplexity, args["coverID"].(int)), true
|
||||||
|
|
||||||
case "Mutation.setFaceGroupLabel":
|
case "Mutation.setFaceGroupLabel":
|
||||||
if e.complexity.Mutation.SetFaceGroupLabel == nil {
|
if e.complexity.Mutation.SetFaceGroupLabel == nil {
|
||||||
break
|
break
|
||||||
|
@ -1783,6 +1811,11 @@ type Mutation {
|
||||||
|
|
||||||
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
||||||
|
|
||||||
|
"Reset the assigned cover photo for an album"
|
||||||
|
resetAlbumCover(albumID: ID!): Album! @isAuthorized
|
||||||
|
"Assign a cover photo to an album"
|
||||||
|
setAlbumCover(coverID: ID!): Album! @isAuthorized
|
||||||
|
|
||||||
"Assign a label to a face group, set label to null to remove the current one"
|
"Assign a label to a face group, set label to null to remove the current one"
|
||||||
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
||||||
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
||||||
|
@ -1911,7 +1944,7 @@ type Album {
|
||||||
paginate: Pagination
|
paginate: Pagination
|
||||||
): [Album!]!
|
): [Album!]!
|
||||||
|
|
||||||
"The album witch contains this album"
|
"The album which contains this album"
|
||||||
parentAlbum: Album
|
parentAlbum: Album
|
||||||
"The user who owns this album"
|
"The user who owns this album"
|
||||||
owner: User!
|
owner: User!
|
||||||
|
@ -1922,6 +1955,8 @@ type Album {
|
||||||
path: [Album!]!
|
path: [Album!]!
|
||||||
|
|
||||||
shares: [ShareToken!]!
|
shares: [ShareToken!]!
|
||||||
|
|
||||||
|
#coverID: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaURL {
|
type MediaURL {
|
||||||
|
@ -2368,6 +2403,21 @@ func (ec *executionContext) field_Mutation_protectShareToken_args(ctx context.Co
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_resetAlbumCover_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 int
|
||||||
|
if tmp, ok := rawArgs["albumID"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("albumID"))
|
||||||
|
arg0, err = ec.unmarshalNID2int(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["albumID"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -2383,6 +2433,21 @@ func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, ra
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_setAlbumCover_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 int
|
||||||
|
if tmp, ok := rawArgs["coverID"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("coverID"))
|
||||||
|
arg0, err = ec.unmarshalNID2int(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["coverID"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_setFaceGroupLabel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_setFaceGroupLabel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -5926,6 +5991,130 @@ func (ec *executionContext) _Mutation_changeUserPreferences(ctx context.Context,
|
||||||
return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res)
|
return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_resetAlbumCover(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_resetAlbumCover_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) {
|
||||||
|
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().ResetAlbumCover(rctx, args["albumID"].(int))
|
||||||
|
}
|
||||||
|
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.IsAuthorized == nil {
|
||||||
|
return nil, errors.New("directive isAuthorized is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.IsAuthorized(ctx, nil, directive0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := directive1(rctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
if tmp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(*models.Album); ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp)
|
||||||
|
})
|
||||||
|
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.(*models.Album)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_setAlbumCover(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_setAlbumCover_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) {
|
||||||
|
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().SetAlbumCover(rctx, args["coverID"].(int))
|
||||||
|
}
|
||||||
|
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.IsAuthorized == nil {
|
||||||
|
return nil, errors.New("directive isAuthorized is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.IsAuthorized(ctx, nil, directive0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := directive1(rctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
if tmp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(*models.Album); ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp)
|
||||||
|
})
|
||||||
|
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.(*models.Album)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_setFaceGroupLabel(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_setFaceGroupLabel(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -10779,6 +10968,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "resetAlbumCover":
|
||||||
|
out.Values[i] = ec._Mutation_resetAlbumCover(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "setAlbumCover":
|
||||||
|
out.Values[i] = ec._Mutation_setAlbumCover(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "setFaceGroupLabel":
|
case "setFaceGroupLabel":
|
||||||
out.Values[i] = ec._Mutation_setFaceGroupLabel(ctx, field)
|
out.Values[i] = ec._Mutation_setFaceGroupLabel(ctx, field)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MyAlbums(db *gorm.DB, user *models.User, order *models.Ordering, paginate *models.Pagination, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error) {
|
||||||
|
if err := user.FillAlbums(db); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(user.Albums) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userAlbumIDs := make([]int, len(user.Albums))
|
||||||
|
for i, album := range user.Albums {
|
||||||
|
userAlbumIDs[i] = album.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
query := db.Model(models.Album{}).Where("id IN (?)", userAlbumIDs)
|
||||||
|
|
||||||
|
if onlyRoot != nil && *onlyRoot {
|
||||||
|
query = query.Where("parent_album_id IS NULL")
|
||||||
|
}
|
||||||
|
|
||||||
|
if showEmpty == nil || !*showEmpty {
|
||||||
|
subQuery := db.Model(&models.Media{}).Where("album_id = albums.id")
|
||||||
|
|
||||||
|
if onlyWithFavorites != nil && *onlyWithFavorites {
|
||||||
|
favoritesSubquery := db.
|
||||||
|
Model(&models.UserMediaData{UserID: user.ID}).
|
||||||
|
Where("user_media_data.media_id = media.id").
|
||||||
|
Where("user_media_data.favorite = true")
|
||||||
|
|
||||||
|
subQuery = subQuery.Where("EXISTS (?)", favoritesSubquery)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.Where("EXISTS (?)", subQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = models.FormatSQL(query, order, paginate)
|
||||||
|
|
||||||
|
var albums []*models.Album
|
||||||
|
if err := query.Find(&albums).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return albums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Album(db *gorm.DB, user *models.User, id int) (*models.Album, error) {
|
||||||
|
var album models.Album
|
||||||
|
if err := db.First(&album, id).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, errors.New("album not found")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ownsAlbum, err := user.OwnsAlbum(db, &album)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ownsAlbum {
|
||||||
|
return nil, errors.New("forbidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &album, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetAlbumCover(db *gorm.DB, user *models.User, mediaID int) (*models.Album, error) {
|
||||||
|
var media models.Media
|
||||||
|
|
||||||
|
if err := db.Find(&media, mediaID).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var album models.Album
|
||||||
|
|
||||||
|
if err := db.Find(&album, &media.AlbumID).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ownsAlbum, err := user.OwnsAlbum(db, &album)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ownsAlbum {
|
||||||
|
return nil, errors.New("forbidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&album).Update("cover_id", mediaID).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &album, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetAlbumCover(db *gorm.DB, user *models.User, albumID int) (*models.Album, error) {
|
||||||
|
var album models.Album
|
||||||
|
if err := db.Find(&album, albumID).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ownsAlbum, err := user.OwnsAlbum(db, &album)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ownsAlbum {
|
||||||
|
return nil, errors.New("forbidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Model(&album).Update("cover_id", nil).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &album, nil
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
package actions_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||||
|
"github.com/photoview/photoview/api/test_utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAlbumCover(t *testing.T) {
|
||||||
|
db := test_utils.DatabaseTest(t)
|
||||||
|
|
||||||
|
rootAlbum := models.Album{
|
||||||
|
Title: "root",
|
||||||
|
Path: "/photos",
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Save(&rootAlbum).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
children := []models.Album{
|
||||||
|
{
|
||||||
|
Title: "child1",
|
||||||
|
Path: "/photos/child1",
|
||||||
|
ParentAlbumID: &rootAlbum.ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "child2",
|
||||||
|
Path: "/photos/child2",
|
||||||
|
ParentAlbumID: &rootAlbum.ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Save(&children).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := []models.Media{
|
||||||
|
{
|
||||||
|
Title: "pic1",
|
||||||
|
Path: "/photos/pic1",
|
||||||
|
AlbumID: rootAlbum.ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic2",
|
||||||
|
Path: "/photos/pic2",
|
||||||
|
AlbumID: rootAlbum.ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic3",
|
||||||
|
Path: "/photos/child1/pic3",
|
||||||
|
AlbumID: children[0].ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic4",
|
||||||
|
Path: "/photos/child1/pic4",
|
||||||
|
AlbumID: children[0].ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic5",
|
||||||
|
Path: "/photos/child2/pic5",
|
||||||
|
AlbumID: children[1].ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic6",
|
||||||
|
Path: "/photos/child2/pic6",
|
||||||
|
AlbumID: children[1].ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Save(&photos).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Model(&children[0]).Update("cover_id", &photos[3].ID).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
photoUrls := []models.MediaURL{
|
||||||
|
{
|
||||||
|
MediaID: photos[0].ID,
|
||||||
|
Media: &photos[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MediaID: photos[1].ID,
|
||||||
|
Media: &photos[1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MediaID: photos[2].ID,
|
||||||
|
Media: &photos[2],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MediaID: photos[3].ID,
|
||||||
|
Media: &photos[3],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MediaID: photos[4].ID,
|
||||||
|
Media: &photos[4],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MediaID: photos[5].ID,
|
||||||
|
Media: &photos[5],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Save(&photoUrls).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user_pass := "password"
|
||||||
|
regularUser, err := models.RegisterUser(db, "user1", &user_pass, false)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Model(®ularUser).Association("Albums").Append(&rootAlbum)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Model(®ularUser).Association("Albums").Append(&children)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single test since we cannot rely on the tests being performed sequentially
|
||||||
|
t.Run("Album get and reset cover photos", func(t *testing.T) {
|
||||||
|
{
|
||||||
|
album, err := actions.Album(db, regularUser, rootAlbum.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
albumThumb, err := album.Thumbnail(db)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Should return pic1 since no coverID has been set
|
||||||
|
assert.EqualValues(t, "pic1", albumThumb.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
album, err := actions.Album(db, regularUser, children[0].ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
albumThumb, err := album.Thumbnail(db)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// coverID has already been set
|
||||||
|
assert.EqualValues(t, "pic4", albumThumb.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAlbum, err := actions.ResetAlbumCover(db, regularUser, children[0].ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Nil(t, resetAlbum.CoverID)
|
||||||
|
|
||||||
|
resetThumb, err := resetAlbum.Thumbnail(db)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "pic3", resetThumb.Title)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Album change cover photos", func(t *testing.T) {
|
||||||
|
assert.Nil(t, children[1].CoverID)
|
||||||
|
|
||||||
|
album, err := actions.SetAlbumCover(db, regularUser, photos[4].ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, children[1].ID, album.ID)
|
||||||
|
assert.NotNil(t, album.CoverID)
|
||||||
|
assert.Equal(t, photos[4].ID, *album.CoverID)
|
||||||
|
|
||||||
|
albumThumb, err := album.Thumbnail(db)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, photos[4].ID, albumThumb.ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ type Album struct {
|
||||||
Owners []User `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
|
Owners []User `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
|
||||||
Path string `gorm:"not null"`
|
Path string `gorm:"not null"`
|
||||||
PathHash string `gorm:"unique"`
|
PathHash string `gorm:"unique"`
|
||||||
|
CoverID *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Album) FilePath() string {
|
func (a *Album) FilePath() string {
|
||||||
|
@ -78,3 +79,31 @@ func GetParentsFromAlbums(db *gorm.DB, filter func(*gorm.DB) *gorm.DB, albumID i
|
||||||
|
|
||||||
return parents, err
|
return parents, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Album) Thumbnail(db *gorm.DB) (*Media, error) {
|
||||||
|
var media Media
|
||||||
|
|
||||||
|
if a.CoverID == nil {
|
||||||
|
if err := db.Raw(`
|
||||||
|
WITH recursive sub_albums AS (
|
||||||
|
SELECT * FROM albums AS root WHERE id = ?
|
||||||
|
UNION ALL
|
||||||
|
SELECT child.* FROM albums AS child JOIN sub_albums ON child.parent_album_id = sub_albums.id
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT * FROM media WHERE media.album_id IN (
|
||||||
|
SELECT id FROM sub_albums
|
||||||
|
) AND media.id IN (
|
||||||
|
SELECT media_id FROM media_urls WHERE media_urls.media_id = media.id
|
||||||
|
) ORDER BY id LIMIT 1
|
||||||
|
`, a.ID).Find(&media).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := db.Where("id = ?", a.CoverID).Find(&media).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &media, nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
api "github.com/photoview/photoview/api/graphql"
|
api "github.com/photoview/photoview/api/graphql"
|
||||||
"github.com/photoview/photoview/api/graphql/auth"
|
"github.com/photoview/photoview/api/graphql/auth"
|
||||||
"github.com/photoview/photoview/api/graphql/models"
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
@ -16,48 +17,7 @@ func (r *queryResolver) MyAlbums(ctx context.Context, order *models.Ordering, pa
|
||||||
return nil, auth.ErrUnauthorized
|
return nil, auth.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := user.FillAlbums(r.Database); err != nil {
|
return actions.MyAlbums(r.Database, user, order, paginate, onlyRoot, showEmpty, onlyWithFavorites)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(user.Albums) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
userAlbumIDs := make([]int, len(user.Albums))
|
|
||||||
for i, album := range user.Albums {
|
|
||||||
userAlbumIDs[i] = album.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
query := r.Database.Model(models.Album{}).Where("id IN (?)", userAlbumIDs)
|
|
||||||
|
|
||||||
if onlyRoot != nil && *onlyRoot == true {
|
|
||||||
query = query.Where("parent_album_id IS NULL")
|
|
||||||
}
|
|
||||||
|
|
||||||
if showEmpty == nil || *showEmpty == false {
|
|
||||||
subQuery := r.Database.Model(&models.Media{}).Where("album_id = albums.id")
|
|
||||||
|
|
||||||
if onlyWithFavorites != nil && *onlyWithFavorites == true {
|
|
||||||
favoritesSubquery := r.Database.
|
|
||||||
Model(&models.UserMediaData{UserID: user.ID}).
|
|
||||||
Where("user_media_data.media_id = media.id").
|
|
||||||
Where("user_media_data.favorite = true")
|
|
||||||
|
|
||||||
subQuery = subQuery.Where("EXISTS (?)", favoritesSubquery)
|
|
||||||
}
|
|
||||||
|
|
||||||
query = query.Where("EXISTS (?)", subQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
query = models.FormatSQL(query, order, paginate)
|
|
||||||
|
|
||||||
var albums []*models.Album
|
|
||||||
if err := query.Find(&albums).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return albums, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Album(ctx context.Context, id int, tokenCredentials *models.ShareTokenCredentials) (*models.Album, error) {
|
func (r *queryResolver) Album(ctx context.Context, id int, tokenCredentials *models.ShareTokenCredentials) (*models.Album, error) {
|
||||||
|
@ -89,24 +49,7 @@ func (r *queryResolver) Album(ctx context.Context, id int, tokenCredentials *mod
|
||||||
return nil, auth.ErrUnauthorized
|
return nil, auth.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
var album models.Album
|
return actions.Album(r.Database, user, id)
|
||||||
if err := r.Database.First(&album, id).Error; err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil, errors.New("album not found")
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ownsAlbum, err := user.OwnsAlbum(r.Database, &album)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ownsAlbum {
|
|
||||||
return nil, errors.New("forbidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &album, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) Album() api.AlbumResolver {
|
func (r *Resolver) Album() api.AlbumResolver {
|
||||||
|
@ -144,29 +87,8 @@ func (r *albumResolver) Media(ctx context.Context, album *models.Album, order *m
|
||||||
return media, nil
|
return media, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *albumResolver) Thumbnail(ctx context.Context, obj *models.Album) (*models.Media, error) {
|
func (r *albumResolver) Thumbnail(ctx context.Context, album *models.Album) (*models.Media, error) {
|
||||||
|
return album.Thumbnail(r.Database)
|
||||||
var media models.Media
|
|
||||||
|
|
||||||
err := r.Database.Raw(`
|
|
||||||
WITH recursive sub_albums AS (
|
|
||||||
SELECT * FROM albums AS root WHERE id = ?
|
|
||||||
UNION ALL
|
|
||||||
SELECT child.* FROM albums AS child JOIN sub_albums ON child.parent_album_id = sub_albums.id
|
|
||||||
)
|
|
||||||
|
|
||||||
SELECT * FROM media WHERE media.album_id IN (
|
|
||||||
SELECT id FROM sub_albums
|
|
||||||
) AND media.id IN (
|
|
||||||
SELECT media_id FROM media_urls WHERE media_urls.media_id = media.id
|
|
||||||
) LIMIT 1
|
|
||||||
`, obj.ID).Find(&media).Error
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &media, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *albumResolver) SubAlbums(ctx context.Context, parent *models.Album, order *models.Ordering, paginate *models.Pagination) ([]*models.Album, error) {
|
func (r *albumResolver) SubAlbums(ctx context.Context, parent *models.Album, order *models.Ordering, paginate *models.Pagination) ([]*models.Album, error) {
|
||||||
|
@ -242,3 +164,22 @@ func (r *albumResolver) Path(ctx context.Context, obj *models.Album) ([]*models.
|
||||||
|
|
||||||
return album_path, nil
|
return album_path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Takes album_id, resets album.cover_id to 0 (null)
|
||||||
|
func (r *mutationResolver) ResetAlbumCover(ctx context.Context, albumID int) (*models.Album, error) {
|
||||||
|
user := auth.UserFromContext(ctx)
|
||||||
|
if user == nil {
|
||||||
|
return nil, errors.New("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions.ResetAlbumCover(r.Database, user, albumID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) SetAlbumCover(ctx context.Context, mediaID int) (*models.Album, error) {
|
||||||
|
user := auth.UserFromContext(ctx)
|
||||||
|
if user == nil {
|
||||||
|
return nil, errors.New("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions.SetAlbumCover(r.Database, user, mediaID)
|
||||||
|
}
|
||||||
|
|
|
@ -142,6 +142,11 @@ type Mutation {
|
||||||
|
|
||||||
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
||||||
|
|
||||||
|
"Reset the assigned cover photo for an album"
|
||||||
|
resetAlbumCover(albumID: ID!): Album! @isAuthorized
|
||||||
|
"Assign a cover photo to an album"
|
||||||
|
setAlbumCover(coverID: ID!): Album! @isAuthorized
|
||||||
|
|
||||||
"Assign a label to a face group, set label to null to remove the current one"
|
"Assign a label to a face group, set label to null to remove the current one"
|
||||||
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
||||||
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
||||||
|
@ -270,7 +275,7 @@ type Album {
|
||||||
paginate: Pagination
|
paginate: Pagination
|
||||||
): [Album!]!
|
): [Album!]!
|
||||||
|
|
||||||
"The album witch contains this album"
|
"The album which contains this album"
|
||||||
parentAlbum: Album
|
parentAlbum: Album
|
||||||
"The user who owns this album"
|
"The user who owns this album"
|
||||||
owner: User!
|
owner: User!
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Photoview - Photo gallery for self-hosted personal servers
|
||||||
|
Documentation=https://photoview.github.io/docs
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/lib/photoview/photoview
|
||||||
|
WorkingDirectory=/usr/lib/photoview
|
||||||
|
User=photoview
|
||||||
|
Group=photoview
|
||||||
|
|
||||||
|
ReadWritePaths=/var/lib/photoview
|
||||||
|
|
||||||
|
EnvironmentFile=/etc/photoview.env
|
||||||
|
CacheDirectory=photoview/media_cache
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1 @@
|
||||||
|
u photoview - "photoview user"
|
|
@ -0,0 +1,2 @@
|
||||||
|
e /var/cache/photoview 0750 photoview photoview
|
||||||
|
e /var/lib/photoview 0750 photoview photoview
|
|
@ -840,6 +840,9 @@
|
||||||
"integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
|
"integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-bigint": {
|
"node_modules/@babel/plugin-syntax-bigint": {
|
||||||
|
@ -945,6 +948,9 @@
|
||||||
"integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
|
"integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-jsx": {
|
"node_modules/@babel/plugin-syntax-jsx": {
|
||||||
|
@ -967,6 +973,9 @@
|
||||||
"integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
|
"integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.10.4"
|
"@babel/helper-plugin-utils": "^7.10.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
|
"node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
|
||||||
|
@ -975,6 +984,9 @@
|
||||||
"integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
|
"integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-numeric-separator": {
|
"node_modules/@babel/plugin-syntax-numeric-separator": {
|
||||||
|
@ -983,6 +995,9 @@
|
||||||
"integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
|
"integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.10.4"
|
"@babel/helper-plugin-utils": "^7.10.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-object-rest-spread": {
|
"node_modules/@babel/plugin-syntax-object-rest-spread": {
|
||||||
|
@ -991,6 +1006,9 @@
|
||||||
"integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
|
"integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-optional-catch-binding": {
|
"node_modules/@babel/plugin-syntax-optional-catch-binding": {
|
||||||
|
@ -999,6 +1017,9 @@
|
||||||
"integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
|
"integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-optional-chaining": {
|
"node_modules/@babel/plugin-syntax-optional-chaining": {
|
||||||
|
@ -1007,6 +1028,9 @@
|
||||||
"integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
|
"integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.8.0"
|
"@babel/helper-plugin-utils": "^7.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-private-property-in-object": {
|
"node_modules/@babel/plugin-syntax-private-property-in-object": {
|
||||||
|
@ -1750,6 +1774,9 @@
|
||||||
"@babel/plugin-transform-dotall-regex": "^7.4.4",
|
"@babel/plugin-transform-dotall-regex": "^7.4.4",
|
||||||
"@babel/types": "^7.4.4",
|
"@babel/types": "^7.4.4",
|
||||||
"esutils": "^2.0.2"
|
"esutils": "^2.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/preset-react": {
|
"node_modules/@babel/preset-react": {
|
||||||
|
@ -2030,7 +2057,10 @@
|
||||||
"node_modules/@graphql-typed-document-node/core": {
|
"node_modules/@graphql-typed-document-node/core": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
||||||
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg=="
|
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@hapi/address": {
|
"node_modules/@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
|
@ -2156,6 +2186,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jest/types/node_modules/chalk": {
|
"node_modules/@jest/types/node_modules/chalk": {
|
||||||
|
@ -2168,6 +2201,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jest/types/node_modules/color-convert": {
|
"node_modules/@jest/types/node_modules/color-convert": {
|
||||||
|
@ -3874,6 +3910,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@testing-library/dom/node_modules/chalk": {
|
"node_modules/@testing-library/dom/node_modules/chalk": {
|
||||||
|
@ -3886,6 +3925,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@testing-library/dom/node_modules/color-convert": {
|
"node_modules/@testing-library/dom/node_modules/color-convert": {
|
||||||
|
@ -3955,6 +3997,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@testing-library/jest-dom/node_modules/chalk": {
|
"node_modules/@testing-library/jest-dom/node_modules/chalk": {
|
||||||
|
@ -5131,6 +5176,10 @@
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
"json-schema-traverse": "^0.4.1",
|
"json-schema-traverse": "^0.4.1",
|
||||||
"uri-js": "^4.2.2"
|
"uri-js": "^4.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ajv-errors": {
|
"node_modules/ajv-errors": {
|
||||||
|
@ -5171,6 +5220,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansi-escapes/node_modules/type-fest": {
|
"node_modules/ansi-escapes/node_modules/type-fest": {
|
||||||
|
@ -5179,6 +5231,9 @@
|
||||||
"integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
|
"integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansi-html": {
|
"node_modules/ansi-html": {
|
||||||
|
@ -6245,6 +6300,7 @@
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
|
||||||
"integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
|
"integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
|
||||||
|
"deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.0.0",
|
"@babel/code-frame": "^7.0.0",
|
||||||
"@babel/parser": "^7.7.0",
|
"@babel/parser": "^7.7.0",
|
||||||
|
@ -6255,6 +6311,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": ">= 4.12.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/babel-extract-comments": {
|
"node_modules/babel-extract-comments": {
|
||||||
|
@ -10390,6 +10449,9 @@
|
||||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react/node_modules/doctrine": {
|
"node_modules/eslint-plugin-react/node_modules/doctrine": {
|
||||||
|
@ -10541,6 +10603,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/mysticatea"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-visitor-keys": {
|
"node_modules/eslint-visitor-keys": {
|
||||||
|
@ -10633,6 +10698,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/chalk": {
|
"node_modules/eslint/node_modules/chalk": {
|
||||||
|
@ -10645,6 +10713,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/color-convert": {
|
"node_modules/eslint/node_modules/color-convert": {
|
||||||
|
@ -11517,7 +11588,8 @@
|
||||||
"node_modules/flatten": {
|
"node_modules/flatten": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
|
||||||
"integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg=="
|
"integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
|
||||||
|
"deprecated": "flatten is deprecated in favor of utility frameworks such as lodash."
|
||||||
},
|
},
|
||||||
"node_modules/flush-write-stream": {
|
"node_modules/flush-write-stream": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
@ -11869,6 +11941,7 @@
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
|
@ -12046,6 +12119,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
|
@ -12989,7 +13065,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz",
|
||||||
"integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==",
|
"integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"husky": "lib/bin.js"
|
"husky": "lib/bin.js"
|
||||||
},
|
},
|
||||||
|
@ -14005,6 +14080,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest-diff/node_modules/chalk": {
|
"node_modules/jest-diff/node_modules/chalk": {
|
||||||
|
@ -14017,6 +14095,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest-diff/node_modules/color-convert": {
|
"node_modules/jest-diff/node_modules/color-convert": {
|
||||||
|
@ -16046,6 +16127,10 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"tiny-warning": "^1.0.3"
|
"tiny-warning": "^1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prop-types": "^15.0.0",
|
||||||
|
"react": "^0.14.0 || ^15.0.0 || ^16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mini-css-extract-plugin": {
|
"node_modules/mini-css-extract-plugin": {
|
||||||
|
@ -17028,6 +17113,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-locate": {
|
"node_modules/p-locate": {
|
||||||
|
@ -19029,6 +19117,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pretty-format/node_modules/color-convert": {
|
"node_modules/pretty-format/node_modules/color-convert": {
|
||||||
|
@ -19610,6 +19701,9 @@
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react-fast-compare": "^3.1.1",
|
"react-fast-compare": "^3.1.1",
|
||||||
"react-side-effect": "^2.1.0"
|
"react-side-effect": "^2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-hook-form": {
|
"node_modules/react-hook-form": {
|
||||||
|
@ -19657,6 +19751,9 @@
|
||||||
"react-is": "^16.6.0",
|
"react-is": "^16.6.0",
|
||||||
"tiny-invariant": "^1.0.2",
|
"tiny-invariant": "^1.0.2",
|
||||||
"tiny-warning": "^1.0.0"
|
"tiny-warning": "^1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
|
@ -19671,6 +19768,9 @@
|
||||||
"react-router": "5.2.0",
|
"react-router": "5.2.0",
|
||||||
"tiny-invariant": "^1.0.2",
|
"tiny-invariant": "^1.0.2",
|
||||||
"tiny-warning": "^1.0.0"
|
"tiny-warning": "^1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom/node_modules/history": {
|
"node_modules/react-router-dom/node_modules/history": {
|
||||||
|
@ -21167,12 +21267,18 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.12.0 || ^17.0.0"
|
"react-is": "^16.12.0 || ^17.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.0.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-side-effect": {
|
"node_modules/react-side-effect": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
||||||
"integrity": "sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg=="
|
"integrity": "sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.3.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-spring": {
|
"node_modules/react-spring": {
|
||||||
"version": "8.0.27",
|
"version": "8.0.27",
|
||||||
|
@ -21492,6 +21598,9 @@
|
||||||
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
|
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/mysticatea"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/regexpu-core": {
|
"node_modules/regexpu-core": {
|
||||||
|
@ -27150,6 +27259,9 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wrap-ansi/node_modules/color-convert": {
|
"node_modules/wrap-ansi/node_modules/color-convert": {
|
||||||
|
@ -28646,7 +28758,8 @@
|
||||||
"@graphql-typed-document-node/core": {
|
"@graphql-typed-document-node/core": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
||||||
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg=="
|
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@hapi/address": {
|
"@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
|
@ -35376,7 +35489,8 @@
|
||||||
"eslint-plugin-react-hooks": {
|
"eslint-plugin-react-hooks": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
|
||||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
|
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"eslint-plugin-testing-library": {
|
"eslint-plugin-testing-library": {
|
||||||
"version": "3.10.2",
|
"version": "3.10.2",
|
||||||
|
@ -43696,7 +43810,8 @@
|
||||||
"react-side-effect": {
|
"react-side-effect": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
||||||
"integrity": "sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg=="
|
"integrity": "sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-spring": {
|
"react-spring": {
|
||||||
"version": "8.0.27",
|
"version": "8.0.27",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^12.0.0",
|
"@testing-library/react": "^12.0.0",
|
||||||
"@testing-library/user-event": "^13.1.9",
|
"@testing-library/user-event": "^13.1.9",
|
||||||
|
"apollo": "^2.33.4",
|
||||||
"husky": "^6.0.0",
|
"husky": "^6.0.0",
|
||||||
"i18next-parser": "^4.2.0",
|
"i18next-parser": "^4.2.0",
|
||||||
"lint-staged": "^11.0.1",
|
"lint-staged": "^11.0.1",
|
||||||
|
|
|
@ -25,6 +25,7 @@ const ALBUM_QUERY = gql`
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
thumbnail {
|
thumbnail {
|
||||||
|
id
|
||||||
thumbnail {
|
thumbnail {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface albumQuery_album_subAlbums_thumbnail_thumbnail {
|
||||||
|
|
||||||
export interface albumQuery_album_subAlbums_thumbnail {
|
export interface albumQuery_album_subAlbums_thumbnail {
|
||||||
__typename: "Media";
|
__typename: "Media";
|
||||||
|
id: string;
|
||||||
/**
|
/**
|
||||||
* URL to display the media in a smaller resolution
|
* URL to display the media in a smaller resolution
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,6 +10,7 @@ const getAlbumsQuery = gql`
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
thumbnail {
|
thumbnail {
|
||||||
|
id
|
||||||
thumbnail {
|
thumbnail {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ export interface getMyAlbums_myAlbums_thumbnail_thumbnail {
|
||||||
|
|
||||||
export interface getMyAlbums_myAlbums_thumbnail {
|
export interface getMyAlbums_myAlbums_thumbnail {
|
||||||
__typename: "Media";
|
__typename: "Media";
|
||||||
|
id: string;
|
||||||
/**
|
/**
|
||||||
* URL to display the media in a smaller resolution
|
* URL to display the media in a smaller resolution
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,6 +27,7 @@ export const SHARE_ALBUM_QUERY = gql`
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
thumbnail {
|
thumbnail {
|
||||||
|
id
|
||||||
thumbnail {
|
thumbnail {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface shareAlbumQuery_album_subAlbums_thumbnail_thumbnail {
|
||||||
|
|
||||||
export interface shareAlbumQuery_album_subAlbums_thumbnail {
|
export interface shareAlbumQuery_album_subAlbums_thumbnail {
|
||||||
__typename: "Media";
|
__typename: "Media";
|
||||||
|
id: string;
|
||||||
/**
|
/**
|
||||||
* URL to display the media in a smaller resolution
|
* URL to display the media in a smaller resolution
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { useMutation, gql } from '@apollo/client'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import { SidebarSection, SidebarSectionTitle } from './SidebarComponents'
|
||||||
|
|
||||||
|
import {
|
||||||
|
setAlbumCover,
|
||||||
|
setAlbumCoverVariables,
|
||||||
|
} from './__generated__/setAlbumCover'
|
||||||
|
import {
|
||||||
|
resetAlbumCover,
|
||||||
|
resetAlbumCoverVariables,
|
||||||
|
} from './__generated__/resetAlbumCover'
|
||||||
|
|
||||||
|
const RESET_ALBUM_COVER_MUTATION = gql`
|
||||||
|
mutation resetAlbumCover($albumID: ID!) {
|
||||||
|
resetAlbumCover(albumID: $albumID) {
|
||||||
|
id
|
||||||
|
thumbnail {
|
||||||
|
id
|
||||||
|
thumbnail {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const SET_ALBUM_COVER_MUTATION = gql`
|
||||||
|
mutation setAlbumCover($coverID: ID!) {
|
||||||
|
setAlbumCover(coverID: $coverID) {
|
||||||
|
id
|
||||||
|
thumbnail {
|
||||||
|
id
|
||||||
|
thumbnail {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
type SidebarPhotoCoverProps = {
|
||||||
|
cover_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SidebarPhotoCover = ({ cover_id }: SidebarPhotoCoverProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const [setAlbumCover] = useMutation<setAlbumCover, setAlbumCoverVariables>(
|
||||||
|
SET_ALBUM_COVER_MUTATION,
|
||||||
|
{
|
||||||
|
variables: {
|
||||||
|
coverID: cover_id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const [buttonDisabled, setButtonDisabled] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setButtonDisabled(false)
|
||||||
|
}, [cover_id])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarSection>
|
||||||
|
<SidebarSectionTitle>
|
||||||
|
{t('sidebar.album.cover_photo', 'Album cover')}
|
||||||
|
</SidebarSectionTitle>
|
||||||
|
<div>
|
||||||
|
<table className="border-collapse w-full">
|
||||||
|
<tfoot>
|
||||||
|
<tr className="text-left border-gray-100 border-b border-t">
|
||||||
|
<td colSpan={2} className="pl-4 py-2">
|
||||||
|
<button
|
||||||
|
className="disabled:opacity-50 text-green-500 font-bold uppercase text-xs"
|
||||||
|
disabled={buttonDisabled}
|
||||||
|
onClick={() => {
|
||||||
|
setButtonDisabled(true),
|
||||||
|
setAlbumCover({
|
||||||
|
variables: {
|
||||||
|
coverID: cover_id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{t('sidebar.album.set_cover', 'Set as album cover photo')}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</SidebarSection>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SidebarAlbumCoverProps = {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SidebarAlbumCover = ({ id }: SidebarAlbumCoverProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const [resetAlbumCover] = useMutation<
|
||||||
|
resetAlbumCover,
|
||||||
|
resetAlbumCoverVariables
|
||||||
|
>(RESET_ALBUM_COVER_MUTATION, {
|
||||||
|
variables: {
|
||||||
|
albumID: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const [buttonDisabled, setButtonDisabled] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setButtonDisabled(false)
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarSection>
|
||||||
|
<SidebarSectionTitle>
|
||||||
|
{t('sidebar.album.album_cover', 'Album cover')}
|
||||||
|
</SidebarSectionTitle>
|
||||||
|
<div>
|
||||||
|
<table className="border-collapse w-full">
|
||||||
|
<tfoot>
|
||||||
|
<tr className="text-left border-gray-100 border-b border-t">
|
||||||
|
<td colSpan={2} className="pl-4 py-2">
|
||||||
|
<button
|
||||||
|
className="disabled:opacity-50 text-red-500 font-bold uppercase text-xs"
|
||||||
|
disabled={buttonDisabled}
|
||||||
|
onClick={() => {
|
||||||
|
setButtonDisabled(true),
|
||||||
|
resetAlbumCover({
|
||||||
|
variables: {
|
||||||
|
albumID: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{t('sidebar.album.reset_cover', 'Reset cover photo')}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</SidebarSection>
|
||||||
|
)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import {
|
||||||
getAlbumSidebar,
|
getAlbumSidebar,
|
||||||
getAlbumSidebarVariables,
|
getAlbumSidebarVariables,
|
||||||
} from './__generated__/getAlbumSidebar'
|
} from './__generated__/getAlbumSidebar'
|
||||||
|
import { SidebarAlbumCover } from './AlbumCovers'
|
||||||
|
|
||||||
const albumQuery = gql`
|
const albumQuery = gql`
|
||||||
query getAlbumSidebar($id: ID!) {
|
query getAlbumSidebar($id: ID!) {
|
||||||
|
@ -46,6 +47,9 @@ const AlbumSidebar = ({ albumId }: AlbumSidebarProps) => {
|
||||||
{/* <h1 className="text-3xl font-semibold">{data.album.title}</h1> */}
|
{/* <h1 className="text-3xl font-semibold">{data.album.title}</h1> */}
|
||||||
<SidebarAlbumShare id={albumId} />
|
<SidebarAlbumShare id={albumId} />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-8">
|
||||||
|
<SidebarAlbumCover id={albumId} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {
|
||||||
|
|
||||||
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
|
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
|
||||||
import SidebarHeader from './SidebarHeader'
|
import SidebarHeader from './SidebarHeader'
|
||||||
|
import { SidebarPhotoCover } from './AlbumCovers'
|
||||||
|
|
||||||
const SIDEBAR_MEDIA_QUERY = gql`
|
const SIDEBAR_MEDIA_QUERY = gql`
|
||||||
query sidebarPhoto($id: ID!) {
|
query sidebarPhoto($id: ID!) {
|
||||||
|
@ -365,6 +366,9 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
|
||||||
<MetadataInfo media={media} />
|
<MetadataInfo media={media} />
|
||||||
<SidebarDownload media={media} />
|
<SidebarDownload media={media} />
|
||||||
<SidebarPhotoShare id={media.id} />
|
<SidebarPhotoShare id={media.id} />
|
||||||
|
<div className="mt-8">
|
||||||
|
<SidebarPhotoCover cover_id={media.id} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,8 +312,7 @@ export const SidebarPhotoShare = ({ id }: SidebarSharePhotoProps) => {
|
||||||
const [
|
const [
|
||||||
loadShares,
|
loadShares,
|
||||||
{ loading: queryLoading, error: sharesError, data: sharesData },
|
{ loading: queryLoading, error: sharesError, data: sharesData },
|
||||||
] =
|
] = useLazyQuery<sidebarGetPhotoShares, sidebarGetPhotoSharesVariables>(
|
||||||
useLazyQuery<sidebarGetPhotoShares, sidebarGetPhotoSharesVariables>(
|
|
||||||
SHARE_PHOTO_QUERY
|
SHARE_PHOTO_QUERY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL mutation operation: resetAlbumCover
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface resetAlbumCover_resetAlbumCover_thumbnail_thumbnail {
|
||||||
|
__typename: "MediaURL";
|
||||||
|
/**
|
||||||
|
* URL for previewing the image
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface resetAlbumCover_resetAlbumCover_thumbnail {
|
||||||
|
__typename: "Media";
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* URL to display the media in a smaller resolution
|
||||||
|
*/
|
||||||
|
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail_thumbnail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface resetAlbumCover_resetAlbumCover {
|
||||||
|
__typename: "Album";
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* An image in this album used for previewing this album
|
||||||
|
*/
|
||||||
|
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface resetAlbumCover {
|
||||||
|
/**
|
||||||
|
* Reset the assigned cover photo for an album
|
||||||
|
*/
|
||||||
|
resetAlbumCover: resetAlbumCover_resetAlbumCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface resetAlbumCoverVariables {
|
||||||
|
albumID: string;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL mutation operation: setAlbumCover
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface setAlbumCover_setAlbumCover_thumbnail_thumbnail {
|
||||||
|
__typename: "MediaURL";
|
||||||
|
/**
|
||||||
|
* URL for previewing the image
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCover_setAlbumCover_thumbnail {
|
||||||
|
__typename: "Media";
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* URL to display the media in a smaller resolution
|
||||||
|
*/
|
||||||
|
thumbnail: setAlbumCover_setAlbumCover_thumbnail_thumbnail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCover_setAlbumCover {
|
||||||
|
__typename: "Album";
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* An image in this album used for previewing this album
|
||||||
|
*/
|
||||||
|
thumbnail: setAlbumCover_setAlbumCover_thumbnail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCover {
|
||||||
|
/**
|
||||||
|
* Assign a cover photo to an album
|
||||||
|
*/
|
||||||
|
setAlbumCover: setAlbumCover_setAlbumCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCoverVariables {
|
||||||
|
coverID: string;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL mutation operation: setAlbumCoverID
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface setAlbumCoverID_setAlbumCoverID {
|
||||||
|
__typename: 'Album'
|
||||||
|
id: string
|
||||||
|
coverID: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCoverID {
|
||||||
|
/**
|
||||||
|
* Assign a cover image to an album, set coverID to -1 to remove the current one
|
||||||
|
*/
|
||||||
|
setAlbumCoverID: setAlbumCoverID_setAlbumCoverID
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface setAlbumCoverIDVariables {
|
||||||
|
albumID: string
|
||||||
|
coverID: string
|
||||||
|
}
|
Loading…
Reference in New Issue