Merge pull request #530 from photoview/improved-timeline
Improved timeline
This commit is contained in:
commit
77e1a45f0c
|
@ -37,6 +37,7 @@ yarn-debug.log*
|
|||
yarn-error.log*
|
||||
.eslintcache
|
||||
|
||||
# vscode
|
||||
# IDEs
|
||||
.vscode
|
||||
__debug_bin
|
||||
.idea
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"eslint.workingDirectories": ["ui"]
|
||||
}
|
|
@ -38,6 +38,8 @@ models:
|
|||
resolver: true
|
||||
type:
|
||||
resolver: true
|
||||
album:
|
||||
resolver: true
|
||||
MediaURL:
|
||||
model: github.com/photoview/photoview/api/graphql/models.MediaURL
|
||||
MediaEXIF:
|
||||
|
|
|
@ -98,6 +98,7 @@ type ComplexityRoot struct {
|
|||
|
||||
Media struct {
|
||||
Album func(childComplexity int) int
|
||||
Date func(childComplexity int) int
|
||||
Downloads func(childComplexity int) int
|
||||
Exif func(childComplexity int) int
|
||||
Faces func(childComplexity int) int
|
||||
|
@ -188,7 +189,7 @@ type ComplexityRoot struct {
|
|||
MyFaceGroups func(childComplexity int, paginate *models.Pagination) int
|
||||
MyMedia func(childComplexity int, order *models.Ordering, paginate *models.Pagination) int
|
||||
MyMediaGeoJSON func(childComplexity int) int
|
||||
MyTimeline func(childComplexity int, paginate *models.Pagination, onlyFavorites *bool) int
|
||||
MyTimeline func(childComplexity int, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) int
|
||||
MyUser func(childComplexity int) int
|
||||
MyUserPreferences func(childComplexity int) int
|
||||
Search func(childComplexity int, query string, limitMedia *int, limitAlbums *int) int
|
||||
|
@ -287,11 +288,12 @@ type MediaResolver interface {
|
|||
Thumbnail(ctx context.Context, obj *models.Media) (*models.MediaURL, error)
|
||||
HighRes(ctx context.Context, obj *models.Media) (*models.MediaURL, error)
|
||||
VideoWeb(ctx context.Context, obj *models.Media) (*models.MediaURL, error)
|
||||
|
||||
Album(ctx context.Context, obj *models.Media) (*models.Album, error)
|
||||
Exif(ctx context.Context, obj *models.Media) (*models.MediaEXIF, error)
|
||||
|
||||
Favorite(ctx context.Context, obj *models.Media) (bool, error)
|
||||
Type(ctx context.Context, obj *models.Media) (models.MediaType, error)
|
||||
|
||||
Shares(ctx context.Context, obj *models.Media) ([]*models.ShareToken, error)
|
||||
Downloads(ctx context.Context, obj *models.Media) ([]*models.MediaDownload, error)
|
||||
Faces(ctx context.Context, obj *models.Media) ([]*models.ImageFace, error)
|
||||
|
@ -332,7 +334,7 @@ type QueryResolver interface {
|
|||
MyMedia(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error)
|
||||
Media(ctx context.Context, id int, tokenCredentials *models.ShareTokenCredentials) (*models.Media, error)
|
||||
MediaList(ctx context.Context, ids []int) ([]*models.Media, error)
|
||||
MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool) ([]*models.TimelineGroup, error)
|
||||
MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error)
|
||||
MyMediaGeoJSON(ctx context.Context) (interface{}, error)
|
||||
MapboxToken(ctx context.Context) (*string, error)
|
||||
ShareToken(ctx context.Context, credentials models.ShareTokenCredentials) (*models.ShareToken, error)
|
||||
|
@ -567,6 +569,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Media.Album(childComplexity), true
|
||||
|
||||
case "Media.date":
|
||||
if e.complexity.Media.Date == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Media.Date(childComplexity), true
|
||||
|
||||
case "Media.downloads":
|
||||
if e.complexity.Media.Downloads == nil {
|
||||
break
|
||||
|
@ -1226,7 +1235,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyTimeline(childComplexity, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool)), true
|
||||
return e.complexity.Query.MyTimeline(childComplexity, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool), args["fromDate"].(*time.Time)), true
|
||||
|
||||
case "Query.myUser":
|
||||
if e.complexity.Query.MyUser == nil {
|
||||
|
@ -1723,7 +1732,15 @@ type Query {
|
|||
"Get a list of media by their ids, user must own the media or be admin"
|
||||
mediaList(ids: [ID!]!): [Media!]!
|
||||
|
||||
myTimeline(paginate: Pagination, onlyFavorites: Boolean): [TimelineGroup!]! @isAuthorized
|
||||
"""
|
||||
Get a list of media, ordered first by day, then by album if multiple media was found for the same day.
|
||||
"""
|
||||
myTimeline(
|
||||
paginate: Pagination,
|
||||
onlyFavorites: Boolean,
|
||||
"Only fetch media that is older than this date"
|
||||
fromDate: Time
|
||||
): [Media!]! @isAuthorized
|
||||
|
||||
"Get media owned by the logged in user, returned in GeoJson format"
|
||||
myMediaGeoJson: Any! @isAuthorized
|
||||
|
@ -1980,6 +1997,8 @@ type Media {
|
|||
videoMetadata: VideoMetadata
|
||||
favorite: Boolean!
|
||||
type: MediaType!
|
||||
"The date the image was shot or the date it was imported as a fallback"
|
||||
date: Time!
|
||||
|
||||
shares: [ShareToken!]!
|
||||
downloads: [MediaDownload!]!
|
||||
|
@ -2843,6 +2862,15 @@ func (ec *executionContext) field_Query_myTimeline_args(ctx context.Context, raw
|
|||
}
|
||||
}
|
||||
args["onlyFavorites"] = arg1
|
||||
var arg2 *time.Time
|
||||
if tmp, ok := rawArgs["fromDate"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fromDate"))
|
||||
arg2, err = ec.unmarshalOTime2ᚖtimeᚐTime(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["fromDate"] = arg2
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -4067,14 +4095,14 @@ func (ec *executionContext) _Media_album(ctx context.Context, field graphql.Coll
|
|||
Object: "Media",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
}
|
||||
|
||||
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.Album, nil
|
||||
return ec.resolvers.Media().Album(rctx, obj)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
@ -4086,9 +4114,9 @@ func (ec *executionContext) _Media_album(ctx context.Context, field graphql.Coll
|
|||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(models.Album)
|
||||
res := resTmp.(*models.Album)
|
||||
fc.Result = res
|
||||
return ec.marshalNAlbum2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||
return ec.marshalNAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Media_exif(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) {
|
||||
|
@ -4225,6 +4253,41 @@ func (ec *executionContext) _Media_type(ctx context.Context, field graphql.Colle
|
|||
return ec.marshalNMediaType2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Media_date(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: true,
|
||||
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.Date(), 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.(time.Time)
|
||||
fc.Result = res
|
||||
return ec.marshalNTime2timeᚐTime(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 {
|
||||
|
@ -7112,7 +7175,7 @@ func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql
|
|||
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.Query().MyTimeline(rctx, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool))
|
||||
return ec.resolvers.Query().MyTimeline(rctx, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool), args["fromDate"].(*time.Time))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAuthorized == nil {
|
||||
|
@ -7128,10 +7191,10 @@ func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql
|
|||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.([]*models.TimelineGroup); ok {
|
||||
if data, ok := tmp.([]*models.Media); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.TimelineGroup`, tmp)
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.Media`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
@ -7143,9 +7206,9 @@ func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql
|
|||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*models.TimelineGroup)
|
||||
res := resTmp.([]*models.Media)
|
||||
fc.Result = res
|
||||
return ec.marshalNTimelineGroup2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐTimelineGroupᚄ(ctx, field.Selections, res)
|
||||
return ec.marshalNMedia2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_myMediaGeoJson(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
|
@ -10576,10 +10639,19 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob
|
|||
return res
|
||||
})
|
||||
case "album":
|
||||
out.Values[i] = ec._Media_album(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
}
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._Media_album(ctx, field, obj)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
}
|
||||
return res
|
||||
})
|
||||
case "exif":
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
|
@ -10621,6 +10693,11 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob
|
|||
}
|
||||
return res
|
||||
})
|
||||
case "date":
|
||||
out.Values[i] = ec._Media_date(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
}
|
||||
case "shares":
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
|
@ -12466,53 +12543,6 @@ func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel as
|
|||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNTimelineGroup2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐTimelineGroupᚄ(ctx context.Context, sel ast.SelectionSet, v []*models.TimelineGroup) graphql.Marshaler {
|
||||
ret := make(graphql.Array, len(v))
|
||||
var wg sync.WaitGroup
|
||||
isLen1 := len(v) == 1
|
||||
if !isLen1 {
|
||||
wg.Add(len(v))
|
||||
}
|
||||
for i := range v {
|
||||
i := i
|
||||
fc := &graphql.FieldContext{
|
||||
Index: &i,
|
||||
Result: &v[i],
|
||||
}
|
||||
ctx := graphql.WithFieldContext(ctx, fc)
|
||||
f := func(i int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if !isLen1 {
|
||||
defer wg.Done()
|
||||
}
|
||||
ret[i] = ec.marshalNTimelineGroup2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐTimelineGroup(ctx, sel, v[i])
|
||||
}
|
||||
if isLen1 {
|
||||
f(i)
|
||||
} else {
|
||||
go f(i)
|
||||
}
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNTimelineGroup2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐTimelineGroup(ctx context.Context, sel ast.SelectionSet, v *models.TimelineGroup) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._TimelineGroup(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNUser2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v models.User) graphql.Marshaler {
|
||||
return ec._User(ctx, sel, &v)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func MyMedia(db *gorm.DB, user *models.User, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error) {
|
||||
if err := user.FillAlbums(db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := db.Where("media.album_id IN (SELECT user_albums.album_id FROM user_albums WHERE user_albums.user_id = ?)", user.ID)
|
||||
query = models.FormatSQL(query, order, paginate)
|
||||
|
||||
var media []*models.Media
|
||||
if err := query.Find(&media).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return media, nil
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
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 TestMyMedia(t *testing.T) {
|
||||
db := test_utils.DatabaseTest(t)
|
||||
|
||||
password := "1234"
|
||||
user, err := models.RegisterUser(db, "user", &password, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
rootAlbum := models.Album{
|
||||
Title: "root",
|
||||
Path: "/photos",
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Save(&rootAlbum).Error)
|
||||
|
||||
childAlbum := models.Album{
|
||||
Title: "subalbum",
|
||||
Path: "/photos/subalbum",
|
||||
ParentAlbumID: &rootAlbum.ID,
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Save(&childAlbum).Error)
|
||||
|
||||
assert.NoError(t, db.Model(&user).Association("Albums").Append(&rootAlbum))
|
||||
assert.NoError(t, db.Model(&user).Association("Albums").Append(&childAlbum))
|
||||
|
||||
media := []models.Media{
|
||||
{
|
||||
Title: "pic1",
|
||||
Path: "/photos/pic1",
|
||||
AlbumID: rootAlbum.ID,
|
||||
},
|
||||
{
|
||||
Title: "pic2",
|
||||
Path: "/photos/pic2",
|
||||
AlbumID: rootAlbum.ID,
|
||||
},
|
||||
{
|
||||
Title: "pic3",
|
||||
Path: "/photos/subalbum/pic3",
|
||||
AlbumID: childAlbum.ID,
|
||||
},
|
||||
{
|
||||
Title: "pic4",
|
||||
Path: "/photos/subalbum/pic4",
|
||||
AlbumID: childAlbum.ID,
|
||||
},
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Save(&media).Error)
|
||||
|
||||
anotherUser, err := models.RegisterUser(db, "user2", &password, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
anotherAlbum := models.Album{
|
||||
Title: "AnotherAlbum",
|
||||
Path: "/another",
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Save(&anotherAlbum).Error)
|
||||
|
||||
anotherMedia := models.Media{
|
||||
Title: "anotherPic",
|
||||
Path: "/another/anotherPic",
|
||||
AlbumID: anotherAlbum.ID,
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Save(&anotherMedia).Error)
|
||||
|
||||
assert.NoError(t, db.Model(&anotherUser).Association("Albums").Append(&anotherAlbum))
|
||||
|
||||
t.Run("Simple query", func(t *testing.T) {
|
||||
myMedia, err := actions.MyMedia(db, user, nil, nil)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, myMedia, 4)
|
||||
})
|
||||
}
|
|
@ -45,6 +45,10 @@ func (m *Media) BeforeSave(tx *gorm.DB) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Media) Date() time.Time {
|
||||
return m.DateShot
|
||||
}
|
||||
|
||||
type MediaType string
|
||||
|
||||
const (
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
api "github.com/photoview/photoview/api/graphql"
|
||||
"github.com/photoview/photoview/api/graphql/auth"
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||
"github.com/photoview/photoview/api/scanner/face_detection"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm/clause"
|
||||
|
@ -19,29 +20,7 @@ func (r *queryResolver) MyMedia(ctx context.Context, order *models.Ordering, pag
|
|||
return nil, errors.New("unauthorized")
|
||||
}
|
||||
|
||||
if err := user.FillAlbums(r.Database); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userAlbumIDs := make([]int, len(user.Albums))
|
||||
for i, album := range user.Albums {
|
||||
userAlbumIDs[i] = album.ID
|
||||
}
|
||||
|
||||
var media []*models.Media
|
||||
|
||||
query := r.Database.
|
||||
Joins("Album").
|
||||
Where("albums.id IN (?)", userAlbumIDs).
|
||||
Where("media.id IN (?)", r.Database.Model(&models.MediaURL{}).Select("id").Where("media_url.media_id = media.id"))
|
||||
|
||||
query = models.FormatSQL(query, order, paginate)
|
||||
|
||||
if err := query.Find(&media).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return media, nil
|
||||
return actions.MyMedia(r.Database, user, order, paginate)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Media(ctx context.Context, id int, tokenCredentials *models.ShareTokenCredentials) (*models.Media, error) {
|
||||
|
@ -115,6 +94,15 @@ func (r *mediaResolver) Type(ctx context.Context, media *models.Media) (models.M
|
|||
return formattedType, nil
|
||||
}
|
||||
|
||||
func (r *mediaResolver) Album(ctx context.Context, obj *models.Media) (*models.Album, error) {
|
||||
var album models.Album
|
||||
err := r.Database.Find(&album, obj.AlbumID).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &album, nil
|
||||
}
|
||||
|
||||
func (r *mediaResolver) Shares(ctx context.Context, media *models.Media) ([]*models.ShareToken, error) {
|
||||
var shareTokens []*models.ShareToken
|
||||
if err := r.Database.Where("media_id = ?", media.ID).Find(&shareTokens).Error; err != nil {
|
||||
|
|
|
@ -2,135 +2,40 @@ package resolvers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/photoview/photoview/api/database"
|
||||
"github.com/photoview/photoview/api/graphql/auth"
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool) ([]*models.TimelineGroup, error) {
|
||||
func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
|
||||
var timelineGroups []*models.TimelineGroup
|
||||
query := r.Database.
|
||||
Joins("JOIN albums ON media.album_id = albums.id").
|
||||
Where("albums.id IN (?)", r.Database.Table("user_albums").Select("user_albums.album_id").Where("user_id = ?", user.ID)).
|
||||
Order("YEAR(media.date_shot) DESC").
|
||||
Order("MONTH(media.date_shot) DESC").
|
||||
Order("DAY(media.date_shot) DESC").
|
||||
Order("albums.title ASC")
|
||||
|
||||
transactionError := r.Database.Transaction(func(tx *gorm.DB) error {
|
||||
// album_id, year, month, day
|
||||
daysQuery := tx.Select(
|
||||
"albums.id AS album_id",
|
||||
fmt.Sprintf("%s AS year", database.DateExtract(tx, database.DateCompYear, "media.date_shot")),
|
||||
fmt.Sprintf("%s AS month", database.DateExtract(tx, database.DateCompMonth, "media.date_shot")),
|
||||
fmt.Sprintf("%s AS day", database.DateExtract(tx, database.DateCompDay, "media.date_shot")),
|
||||
).
|
||||
Table("media").
|
||||
Joins("JOIN albums ON media.album_id = albums.id").
|
||||
Where("albums.id IN (?)", tx.Table("user_albums").Select("user_albums.album_id").Where("user_id = ?", user.ID))
|
||||
|
||||
if onlyFavorites != nil && *onlyFavorites == true {
|
||||
daysQuery.Where("media.id IN (?)", tx.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
|
||||
}
|
||||
|
||||
if paginate != nil {
|
||||
if paginate.Limit != nil {
|
||||
daysQuery.Limit(*paginate.Limit)
|
||||
}
|
||||
|
||||
if paginate.Offset != nil {
|
||||
daysQuery.Offset(*paginate.Offset)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := daysQuery.Group("albums.id").Group(
|
||||
fmt.Sprintf("%s, %s, %s",
|
||||
database.DateExtract(tx, database.DateCompYear, "media.date_shot"),
|
||||
database.DateExtract(tx, database.DateCompMonth, "media.date_shot"),
|
||||
database.DateExtract(tx, database.DateCompDay, "media.date_shot")),
|
||||
).
|
||||
Order(
|
||||
fmt.Sprintf("%s DESC, %s DESC, %s DESC",
|
||||
database.DateExtract(tx, database.DateCompYear, "media.date_shot"),
|
||||
database.DateExtract(tx, database.DateCompMonth, "media.date_shot"),
|
||||
database.DateExtract(tx, database.DateCompDay, "media.date_shot")),
|
||||
).Rows()
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type group struct {
|
||||
albumID int
|
||||
year int
|
||||
month int
|
||||
day int
|
||||
}
|
||||
|
||||
dbGroups := make([]group, 0)
|
||||
|
||||
for rows.Next() {
|
||||
var g group
|
||||
rows.Scan(&g.albumID, &g.year, &g.month, &g.day)
|
||||
dbGroups = append(dbGroups, g)
|
||||
}
|
||||
|
||||
timelineGroups = make([]*models.TimelineGroup, len(dbGroups))
|
||||
|
||||
for i, group := range dbGroups {
|
||||
|
||||
// Fill album
|
||||
var groupAlbum models.Album
|
||||
if err := tx.First(&groupAlbum, group.albumID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fill media
|
||||
var groupMedia []*models.Media
|
||||
mediaQuery := tx.Model(&models.Media{}).
|
||||
Where("album_id = ?", group.albumID).
|
||||
Where(fmt.Sprintf("%s = ?", database.DateExtract(tx, database.DateCompYear, "media.date_shot")), group.year).
|
||||
Where(fmt.Sprintf("%s = ?", database.DateExtract(tx, database.DateCompMonth, "media.date_shot")), group.month).
|
||||
Where(fmt.Sprintf("%s = ?", database.DateExtract(tx, database.DateCompDay, "media.date_shot")), group.day).
|
||||
Order("date_shot DESC")
|
||||
|
||||
if onlyFavorites != nil && *onlyFavorites == true {
|
||||
mediaQuery.Where("media.id IN (?)", tx.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
|
||||
}
|
||||
|
||||
if err := mediaQuery.Limit(5).Find(&groupMedia).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get total media count
|
||||
var totalMedia int64
|
||||
if err := mediaQuery.Count(&totalMedia).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var date time.Time = groupMedia[0].DateShot
|
||||
date = time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
|
||||
|
||||
timelineGroup := models.TimelineGroup{
|
||||
Album: &groupAlbum,
|
||||
Media: groupMedia,
|
||||
MediaTotal: int(totalMedia),
|
||||
Date: date,
|
||||
}
|
||||
|
||||
timelineGroups[i] = &timelineGroup
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if transactionError != nil {
|
||||
return nil, transactionError
|
||||
if fromDate != nil {
|
||||
query = query.Where("media.date_shot < ?", fromDate)
|
||||
}
|
||||
|
||||
return timelineGroups, nil
|
||||
if onlyFavorites != nil && *onlyFavorites == true {
|
||||
query = query.Where("media.id IN (?)", r.Database.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
|
||||
}
|
||||
|
||||
query = models.FormatSQL(query, nil, paginate)
|
||||
|
||||
var media []*models.Media
|
||||
if err := query.Find(&media).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return media, nil
|
||||
}
|
||||
|
|
|
@ -63,7 +63,15 @@ type Query {
|
|||
"Get a list of media by their ids, user must own the media or be admin"
|
||||
mediaList(ids: [ID!]!): [Media!]!
|
||||
|
||||
myTimeline(paginate: Pagination, onlyFavorites: Boolean): [TimelineGroup!]! @isAuthorized
|
||||
"""
|
||||
Get a list of media, ordered first by day, then by album if multiple media was found for the same day.
|
||||
"""
|
||||
myTimeline(
|
||||
paginate: Pagination,
|
||||
onlyFavorites: Boolean,
|
||||
"Only fetch media that is older than this date"
|
||||
fromDate: Time
|
||||
): [Media!]! @isAuthorized
|
||||
|
||||
"Get media owned by the logged in user, returned in GeoJson format"
|
||||
myMediaGeoJson: Any! @isAuthorized
|
||||
|
@ -318,6 +326,8 @@ type Media {
|
|||
videoMetadata: VideoMetadata
|
||||
favorite: Boolean!
|
||||
type: MediaType!
|
||||
"The date the image was shot or the date it was imported as a fallback"
|
||||
date: Time!
|
||||
|
||||
shares: [ShareToken!]!
|
||||
downloads: [MediaDownload!]!
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -63,7 +63,7 @@
|
|||
"lint:types": "tsc --noemit",
|
||||
"jest": "craco test --setupFilesAfterEnv ./testing/setupTests.ts",
|
||||
"jest:ci": "CI=true craco test --setupFilesAfterEnv ./testing/setupTests.ts --verbose --ci --coverage",
|
||||
"genSchemaTypes": "npx apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts",
|
||||
"genSchemaTypes": "apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts",
|
||||
"extractTranslations": "i18next -c i18next-parser.config.js",
|
||||
"prepare": "(cd .. && npx husky install)"
|
||||
},
|
||||
|
@ -75,7 +75,9 @@
|
|||
"husky": "^6.0.0",
|
||||
"i18next-parser": "^4.2.0",
|
||||
"lint-staged": "^11.0.1",
|
||||
"tsc-files": "^1.1.2"
|
||||
"tsc-files": "^1.1.2",
|
||||
"apollo": "2.33.4",
|
||||
"apollo-language-server": "1.26.3"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5",
|
||||
|
|
|
@ -3,102 +3,102 @@
|
|||
// @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;
|
||||
/**
|
||||
* 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 +106,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;
|
||||
}
|
||||
|
|
|
@ -8,35 +8,35 @@
|
|||
// ====================================================
|
||||
|
||||
export interface getMyAlbums_myAlbums_thumbnail_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
__typename: "MediaURL";
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface getMyAlbums_myAlbums_thumbnail {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: getMyAlbums_myAlbums_thumbnail_thumbnail | null
|
||||
thumbnail: getMyAlbums_myAlbums_thumbnail_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface getMyAlbums_myAlbums {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
title: string;
|
||||
/**
|
||||
* An image in this album used for previewing this album
|
||||
*/
|
||||
thumbnail: getMyAlbums_myAlbums_thumbnail | null
|
||||
thumbnail: getMyAlbums_myAlbums_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface getMyAlbums {
|
||||
/**
|
||||
* List of albums owned by the logged in user.
|
||||
*/
|
||||
myAlbums: getMyAlbums_myAlbums[]
|
||||
myAlbums: getMyAlbums_myAlbums[];
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
// ====================================================
|
||||
|
||||
export interface CheckInitialSetup_siteInfo {
|
||||
__typename: 'SiteInfo'
|
||||
__typename: "SiteInfo";
|
||||
/**
|
||||
* Whether or not the initial setup wizard should be shown
|
||||
*/
|
||||
initialSetup: boolean
|
||||
initialSetup: boolean;
|
||||
}
|
||||
|
||||
export interface CheckInitialSetup {
|
||||
siteInfo: CheckInitialSetup_siteInfo
|
||||
siteInfo: CheckInitialSetup_siteInfo;
|
||||
}
|
||||
|
|
|
@ -3,80 +3,80 @@
|
|||
// @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;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -8,59 +8,59 @@
|
|||
// ====================================================
|
||||
|
||||
export interface myFaces_myFaceGroups_imageFaces_rectangle {
|
||||
__typename: 'FaceRectangle'
|
||||
minX: number
|
||||
maxX: number
|
||||
minY: number
|
||||
maxY: number
|
||||
__typename: "FaceRectangle";
|
||||
minX: number;
|
||||
maxX: number;
|
||||
minY: number;
|
||||
maxY: number;
|
||||
}
|
||||
|
||||
export interface myFaces_myFaceGroups_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 myFaces_myFaceGroups_imageFaces_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
title: string
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
title: string;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: myFaces_myFaceGroups_imageFaces_media_thumbnail | null
|
||||
thumbnail: myFaces_myFaceGroups_imageFaces_media_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface myFaces_myFaceGroups_imageFaces {
|
||||
__typename: 'ImageFace'
|
||||
id: string
|
||||
rectangle: myFaces_myFaceGroups_imageFaces_rectangle
|
||||
media: myFaces_myFaceGroups_imageFaces_media
|
||||
__typename: "ImageFace";
|
||||
id: string;
|
||||
rectangle: myFaces_myFaceGroups_imageFaces_rectangle;
|
||||
media: myFaces_myFaceGroups_imageFaces_media;
|
||||
}
|
||||
|
||||
export interface myFaces_myFaceGroups {
|
||||
__typename: 'FaceGroup'
|
||||
id: string
|
||||
label: string | null
|
||||
imageFaceCount: number
|
||||
imageFaces: myFaces_myFaceGroups_imageFaces[]
|
||||
__typename: "FaceGroup";
|
||||
id: string;
|
||||
label: string | null;
|
||||
imageFaceCount: number;
|
||||
imageFaces: myFaces_myFaceGroups_imageFaces[];
|
||||
}
|
||||
|
||||
export interface myFaces {
|
||||
myFaceGroups: myFaces_myFaceGroups[]
|
||||
myFaceGroups: myFaces_myFaceGroups[];
|
||||
}
|
||||
|
||||
export interface myFacesVariables {
|
||||
limit?: number | null
|
||||
offset?: number | null
|
||||
limit?: number | null;
|
||||
offset?: number | null;
|
||||
}
|
||||
|
|
|
@ -3,86 +3,86 @@
|
|||
// @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;
|
||||
/**
|
||||
* 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[];
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
// ====================================================
|
||||
|
||||
export interface changeUserPassword_updateUser {
|
||||
__typename: 'User'
|
||||
id: string
|
||||
__typename: "User";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface changeUserPassword {
|
||||
updateUser: changeUserPassword_updateUser
|
||||
updateUser: changeUserPassword_updateUser;
|
||||
}
|
||||
|
||||
export interface changeUserPasswordVariables {
|
||||
userId: string
|
||||
password: string
|
||||
userId: string;
|
||||
password: string;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
// ====================================================
|
||||
|
||||
export interface createUser_createUser {
|
||||
__typename: 'User'
|
||||
id: string
|
||||
username: string
|
||||
admin: boolean
|
||||
__typename: "User";
|
||||
id: string;
|
||||
username: string;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
export interface createUser {
|
||||
createUser: createUser_createUser
|
||||
createUser: createUser_createUser;
|
||||
}
|
||||
|
||||
export interface createUserVariables {
|
||||
username: string
|
||||
admin: boolean
|
||||
username: string;
|
||||
admin: boolean;
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
// ====================================================
|
||||
|
||||
export interface deleteUser_deleteUser {
|
||||
__typename: 'User'
|
||||
id: string
|
||||
username: string
|
||||
__typename: "User";
|
||||
id: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface deleteUser {
|
||||
deleteUser: deleteUser_deleteUser
|
||||
deleteUser: deleteUser_deleteUser;
|
||||
}
|
||||
|
||||
export interface deleteUserVariables {
|
||||
id: string
|
||||
id: string;
|
||||
}
|
||||
|
|
|
@ -8,18 +8,18 @@
|
|||
// ====================================================
|
||||
|
||||
export interface updateUser_updateUser {
|
||||
__typename: 'User'
|
||||
id: string
|
||||
username: string
|
||||
admin: boolean
|
||||
__typename: "User";
|
||||
id: string;
|
||||
username: string;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
export interface updateUser {
|
||||
updateUser: updateUser_updateUser
|
||||
updateUser: updateUser_updateUser;
|
||||
}
|
||||
|
||||
export interface updateUserVariables {
|
||||
id: string
|
||||
username?: string | null
|
||||
admin?: boolean | null
|
||||
id: string;
|
||||
username?: string | null;
|
||||
admin?: boolean | null;
|
||||
}
|
||||
|
|
|
@ -3,22 +3,22 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { LanguageTranslation } from './../../../__generated__/globalTypes'
|
||||
import { LanguageTranslation } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: changeUserPreferences
|
||||
// ====================================================
|
||||
|
||||
export interface changeUserPreferences_changeUserPreferences {
|
||||
__typename: 'UserPreferences'
|
||||
id: string
|
||||
language: LanguageTranslation | null
|
||||
__typename: "UserPreferences";
|
||||
id: string;
|
||||
language: LanguageTranslation | null;
|
||||
}
|
||||
|
||||
export interface changeUserPreferences {
|
||||
changeUserPreferences: changeUserPreferences_changeUserPreferences
|
||||
changeUserPreferences: changeUserPreferences_changeUserPreferences;
|
||||
}
|
||||
|
||||
export interface changeUserPreferencesVariables {
|
||||
language?: string | null
|
||||
language?: string | null;
|
||||
}
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { LanguageTranslation } from './../../../__generated__/globalTypes'
|
||||
import { LanguageTranslation } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: myUserPreferences
|
||||
// ====================================================
|
||||
|
||||
export interface myUserPreferences_myUserPreferences {
|
||||
__typename: 'UserPreferences'
|
||||
id: string
|
||||
language: LanguageTranslation | null
|
||||
__typename: "UserPreferences";
|
||||
id: string;
|
||||
language: LanguageTranslation | null;
|
||||
}
|
||||
|
||||
export interface myUserPreferences {
|
||||
myUserPreferences: myUserPreferences_myUserPreferences
|
||||
myUserPreferences: myUserPreferences_myUserPreferences;
|
||||
}
|
||||
|
|
|
@ -3,172 +3,172 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MediaType } from './../../../__generated__/globalTypes'
|
||||
import { MediaType } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: SharePageToken
|
||||
// ====================================================
|
||||
|
||||
export interface SharePageToken_shareToken_album {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface SharePageToken_shareToken_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 SharePageToken_shareToken_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 SharePageToken_shareToken_media_downloads {
|
||||
__typename: 'MediaDownload'
|
||||
title: string
|
||||
mediaUrl: SharePageToken_shareToken_media_downloads_mediaUrl
|
||||
__typename: "MediaDownload";
|
||||
title: string;
|
||||
mediaUrl: SharePageToken_shareToken_media_downloads_mediaUrl;
|
||||
}
|
||||
|
||||
export interface SharePageToken_shareToken_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 SharePageToken_shareToken_media_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 SharePageToken_shareToken_media_exif {
|
||||
__typename: 'MediaEXIF'
|
||||
id: string
|
||||
__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;
|
||||
}
|
||||
|
||||
export interface SharePageToken_shareToken_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
title: string
|
||||
type: MediaType
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
title: string;
|
||||
type: MediaType;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: SharePageToken_shareToken_media_thumbnail | null
|
||||
downloads: SharePageToken_shareToken_media_downloads[]
|
||||
thumbnail: SharePageToken_shareToken_media_thumbnail | null;
|
||||
downloads: SharePageToken_shareToken_media_downloads[];
|
||||
/**
|
||||
* URL to display the photo in full resolution, will be null for videos
|
||||
*/
|
||||
highRes: SharePageToken_shareToken_media_highRes | null
|
||||
highRes: SharePageToken_shareToken_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: SharePageToken_shareToken_media_videoWeb | null
|
||||
exif: SharePageToken_shareToken_media_exif | null
|
||||
videoWeb: SharePageToken_shareToken_media_videoWeb | null;
|
||||
exif: SharePageToken_shareToken_media_exif | null;
|
||||
}
|
||||
|
||||
export interface SharePageToken_shareToken {
|
||||
__typename: 'ShareToken'
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
token: string;
|
||||
/**
|
||||
* The album this token shares
|
||||
*/
|
||||
album: SharePageToken_shareToken_album | null
|
||||
album: SharePageToken_shareToken_album | null;
|
||||
/**
|
||||
* The media this token shares
|
||||
*/
|
||||
media: SharePageToken_shareToken_media | null
|
||||
media: SharePageToken_shareToken_media | null;
|
||||
}
|
||||
|
||||
export interface SharePageToken {
|
||||
shareToken: SharePageToken_shareToken
|
||||
shareToken: SharePageToken_shareToken;
|
||||
}
|
||||
|
||||
export interface SharePageTokenVariables {
|
||||
token: string
|
||||
password?: string | null
|
||||
token: string;
|
||||
password?: string | null;
|
||||
}
|
||||
|
|
|
@ -3,179 +3,179 @@
|
|||
// @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 {
|
||||
__typename: 'MediaEXIF'
|
||||
__typename: "MediaEXIF";
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
export interface shareAlbumQuery_album_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
title: string
|
||||
type: MediaType
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
title: string;
|
||||
type: MediaType;
|
||||
/**
|
||||
* 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 +183,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;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from 'react'
|
||||
import Layout from '../../components/layout/Layout'
|
||||
import TimelineGallery from '../../components/timelineGallery/TimelineGallery'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import TimelineGallery from '../../components/timelineGallery/TimelineGallery'
|
||||
|
||||
const PhotosPage = () => {
|
||||
const TimelinePage = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout title={t('photos_page.title', 'Photos')}>
|
||||
<Layout title={t('photos_page.title', 'Timeline')}>
|
||||
<TimelineGallery />
|
||||
</Layout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PhotosPage
|
||||
export default TimelinePage
|
|
@ -8,34 +8,34 @@
|
|||
//==============================================================
|
||||
|
||||
export enum LanguageTranslation {
|
||||
Danish = 'Danish',
|
||||
English = 'English',
|
||||
French = 'French',
|
||||
German = 'German',
|
||||
Italian = 'Italian',
|
||||
Polish = 'Polish',
|
||||
Portuguese = 'Portuguese',
|
||||
Russian = 'Russian',
|
||||
SimplifiedChinese = 'SimplifiedChinese',
|
||||
Spanish = 'Spanish',
|
||||
Swedish = 'Swedish',
|
||||
TraditionalChinese = 'TraditionalChinese',
|
||||
Danish = "Danish",
|
||||
English = "English",
|
||||
French = "French",
|
||||
German = "German",
|
||||
Italian = "Italian",
|
||||
Polish = "Polish",
|
||||
Portuguese = "Portuguese",
|
||||
Russian = "Russian",
|
||||
SimplifiedChinese = "SimplifiedChinese",
|
||||
Spanish = "Spanish",
|
||||
Swedish = "Swedish",
|
||||
TraditionalChinese = "TraditionalChinese",
|
||||
}
|
||||
|
||||
export enum MediaType {
|
||||
Photo = 'Photo',
|
||||
Video = 'Video',
|
||||
Photo = "Photo",
|
||||
Video = "Video",
|
||||
}
|
||||
|
||||
export enum NotificationType {
|
||||
Close = 'Close',
|
||||
Message = 'Message',
|
||||
Progress = 'Progress',
|
||||
Close = "Close",
|
||||
Message = "Message",
|
||||
Progress = "Progress",
|
||||
}
|
||||
|
||||
export enum OrderDirection {
|
||||
ASC = 'ASC',
|
||||
DESC = 'DESC',
|
||||
ASC = "ASC",
|
||||
DESC = "DESC",
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { LanguageTranslation } from './globalTypes'
|
||||
import { LanguageTranslation } from "./globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: siteTranslation
|
||||
// ====================================================
|
||||
|
||||
export interface siteTranslation_myUserPreferences {
|
||||
__typename: 'UserPreferences'
|
||||
id: string
|
||||
language: LanguageTranslation | null
|
||||
__typename: "UserPreferences";
|
||||
id: string;
|
||||
language: LanguageTranslation | null;
|
||||
}
|
||||
|
||||
export interface siteTranslation {
|
||||
myUserPreferences: siteTranslation_myUserPreferences
|
||||
myUserPreferences: siteTranslation_myUserPreferences;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { ReactComponent as DirectionIcon } from './icons/direction-arrow.svg'
|
|||
|
||||
import Dropdown from '../../primitives/form/Dropdown'
|
||||
|
||||
type FavoriteCheckboxProps = {
|
||||
export type FavoriteCheckboxProps = {
|
||||
onlyFavorites: boolean
|
||||
setOnlyFavorites(favorites: boolean): void
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ const SortingOptions = ({ setOrdering, ordering }: SortingOptionsProps) => {
|
|||
<fieldset>
|
||||
<legend id="filter_group_sort-label" className="inline-block mb-1">
|
||||
<SortingIcon
|
||||
className="inline-block align-baseline mr-1"
|
||||
className="inline-block align-baseline mr-1 mt-1"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{t('album_filter.sort', 'Sort')}</span>
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
// ====================================================
|
||||
|
||||
export interface albumPathQuery_album_path {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface albumPathQuery_album {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
path: albumPathQuery_album_path[]
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
path: albumPathQuery_album_path[];
|
||||
}
|
||||
|
||||
export interface albumPathQuery {
|
||||
|
@ -24,9 +24,9 @@ export interface albumPathQuery {
|
|||
* 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: albumPathQuery_album
|
||||
album: albumPathQuery_album;
|
||||
}
|
||||
|
||||
export interface albumPathQueryVariables {
|
||||
id: string
|
||||
id: string;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ export const MainMenu = () => {
|
|||
<div className="fixed w-full bottom-0 lg:bottom-auto lg:top-[84px] z-30 bg-white shadow-separator lg:shadow-none lg:w-[240px] lg:ml-8 lg:mr-5 flex-shrink-0">
|
||||
<ul className="flex justify-around py-2 px-2 max-w-lg mx-auto lg:flex-col lg:p-0">
|
||||
<MenuButton
|
||||
to="/photos"
|
||||
to="/timeline"
|
||||
exact
|
||||
label={t('sidemenu.photos', 'Timeline')}
|
||||
background="#8ac5f4"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
// ====================================================
|
||||
|
||||
export interface faceDetectionEnabled_siteInfo {
|
||||
__typename: 'SiteInfo'
|
||||
__typename: "SiteInfo";
|
||||
/**
|
||||
* Whether or not face detection is enabled and working
|
||||
*/
|
||||
faceDetectionEnabled: boolean
|
||||
faceDetectionEnabled: boolean;
|
||||
}
|
||||
|
||||
export interface faceDetectionEnabled {
|
||||
siteInfo: faceDetectionEnabled_siteInfo
|
||||
siteInfo: faceDetectionEnabled_siteInfo;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,27 +3,27 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { NotificationType } from './../../../__generated__/globalTypes'
|
||||
import { NotificationType } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL subscription operation: notificationSubscription
|
||||
// ====================================================
|
||||
|
||||
export interface notificationSubscription_notification {
|
||||
__typename: 'Notification'
|
||||
key: string
|
||||
type: NotificationType
|
||||
header: string
|
||||
content: string
|
||||
progress: number | null
|
||||
positive: boolean
|
||||
negative: boolean
|
||||
__typename: "Notification";
|
||||
key: string;
|
||||
type: NotificationType;
|
||||
header: string;
|
||||
content: string;
|
||||
progress: number | null;
|
||||
positive: boolean;
|
||||
negative: boolean;
|
||||
/**
|
||||
* Time in milliseconds before the notification will close
|
||||
*/
|
||||
timeout: number | null
|
||||
timeout: number | null;
|
||||
}
|
||||
|
||||
export interface notificationSubscription {
|
||||
notification: notificationSubscription_notification
|
||||
notification: notificationSubscription_notification;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ const Gallery = styled.div`
|
|||
}
|
||||
`
|
||||
|
||||
const PhotoFiller = styled.div`
|
||||
export const PhotoFiller = styled.div`
|
||||
height: 200px;
|
||||
flex-grow: 999999;
|
||||
`
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
// ====================================================
|
||||
|
||||
export interface markMediaFavorite_favoriteMedia {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
favorite: boolean
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
favorite: boolean;
|
||||
}
|
||||
|
||||
export interface markMediaFavorite {
|
||||
/**
|
||||
* Mark or unmark a media as being a favorite
|
||||
*/
|
||||
favoriteMedia: markMediaFavorite_favoriteMedia
|
||||
favoriteMedia: markMediaFavorite_favoriteMedia;
|
||||
}
|
||||
|
||||
export interface markMediaFavoriteVariables {
|
||||
mediaId: string
|
||||
favorite: boolean
|
||||
mediaId: string;
|
||||
favorite: boolean;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@ const AlbumsPage = React.lazy(
|
|||
() => import('../../Pages/AllAlbumsPage/AlbumsPage')
|
||||
)
|
||||
const AlbumPage = React.lazy(() => import('../../Pages/AlbumPage/AlbumPage'))
|
||||
const PhotosPage = React.lazy(() => import('../../Pages/PhotosPage/PhotosPage'))
|
||||
const TimelinePage = React.lazy(
|
||||
() => import('../../Pages/TimelinePage/TimelinePage')
|
||||
)
|
||||
const PlacesPage = React.lazy(() => import('../../Pages/PlacesPage/PlacesPage'))
|
||||
const SharePage = React.lazy(() => import('../../Pages/SharePage/SharePage'))
|
||||
const PeoplePage = React.lazy(() => import('../../Pages/PeoplePage/PeoplePage'))
|
||||
|
@ -49,11 +51,17 @@ const Routes = () => {
|
|||
<Route path="/share" component={SharePage} />
|
||||
<AuthorizedRoute exact path="/albums" component={AlbumsPage} />
|
||||
<AuthorizedRoute path="/album/:id" component={AlbumPage} />
|
||||
<AuthorizedRoute path="/photos" component={PhotosPage} />
|
||||
<AuthorizedRoute path="/timeline" component={TimelinePage} />
|
||||
<AuthorizedRoute path="/places" component={PlacesPage} />
|
||||
<AuthorizedRoute path="/people/:person?" component={PeoplePage} />
|
||||
<AuthorizedRoute path="/settings" component={SettingsPage} />
|
||||
<Route path="/" exact render={() => <Redirect to="/photos" />} />
|
||||
<Route path="/" exact render={() => <Redirect to="/timeline" />} />
|
||||
{/* For backwards compatibility */}
|
||||
<Route
|
||||
path="/photos"
|
||||
exact
|
||||
render={() => <Redirect to="/timeline" />}
|
||||
/>
|
||||
<Route
|
||||
render={() => (
|
||||
<div>{t('routes.page_not_found', 'Page not found')}</div>
|
||||
|
|
|
@ -8,38 +8,38 @@
|
|||
// ====================================================
|
||||
|
||||
export interface resetAlbumCover_resetAlbumCover_thumbnail_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
__typename: "MediaURL";
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface resetAlbumCover_resetAlbumCover_thumbnail {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail_thumbnail | null
|
||||
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface resetAlbumCover_resetAlbumCover {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
/**
|
||||
* An image in this album used for previewing this album
|
||||
*/
|
||||
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail | null
|
||||
thumbnail: resetAlbumCover_resetAlbumCover_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface resetAlbumCover {
|
||||
/**
|
||||
* Reset the assigned cover photo for an album
|
||||
*/
|
||||
resetAlbumCover: resetAlbumCover_resetAlbumCover
|
||||
resetAlbumCover: resetAlbumCover_resetAlbumCover;
|
||||
}
|
||||
|
||||
export interface resetAlbumCoverVariables {
|
||||
albumID: string
|
||||
albumID: string;
|
||||
}
|
||||
|
|
|
@ -8,38 +8,38 @@
|
|||
// ====================================================
|
||||
|
||||
export interface setAlbumCover_setAlbumCover_thumbnail_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
__typename: "MediaURL";
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface setAlbumCover_setAlbumCover_thumbnail {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: setAlbumCover_setAlbumCover_thumbnail_thumbnail | null
|
||||
thumbnail: setAlbumCover_setAlbumCover_thumbnail_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface setAlbumCover_setAlbumCover {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
/**
|
||||
* An image in this album used for previewing this album
|
||||
*/
|
||||
thumbnail: setAlbumCover_setAlbumCover_thumbnail | null
|
||||
thumbnail: setAlbumCover_setAlbumCover_thumbnail | null;
|
||||
}
|
||||
|
||||
export interface setAlbumCover {
|
||||
/**
|
||||
* Assign a cover photo to an album
|
||||
*/
|
||||
setAlbumCover: setAlbumCover_setAlbumCover
|
||||
setAlbumCover: setAlbumCover_setAlbumCover;
|
||||
}
|
||||
|
||||
export interface setAlbumCoverVariables {
|
||||
coverID: string
|
||||
coverID: string;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebarAlbumAddShare_shareAlbum {
|
||||
__typename: 'ShareToken'
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface sidebarAlbumAddShare {
|
||||
/**
|
||||
* Generate share token for album
|
||||
*/
|
||||
shareAlbum: sidebarAlbumAddShare_shareAlbum
|
||||
shareAlbum: sidebarAlbumAddShare_shareAlbum;
|
||||
}
|
||||
|
||||
export interface sidebarAlbumAddShareVariables {
|
||||
id: string
|
||||
password?: string | null
|
||||
expire?: any | null
|
||||
id: string;
|
||||
password?: string | null;
|
||||
expire?: any | null;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebarGetAlbumShares_album_shares {
|
||||
__typename: 'ShareToken'
|
||||
id: string
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
id: string;
|
||||
token: string;
|
||||
/**
|
||||
* Whether or not a password is needed to access the share
|
||||
*/
|
||||
hasPassword: boolean
|
||||
hasPassword: boolean;
|
||||
}
|
||||
|
||||
export interface sidebarGetAlbumShares_album {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
shares: sidebarGetAlbumShares_album_shares[]
|
||||
__typename: "Album";
|
||||
id: string;
|
||||
shares: sidebarGetAlbumShares_album_shares[];
|
||||
}
|
||||
|
||||
export interface sidebarGetAlbumShares {
|
||||
|
@ -28,9 +28,9 @@ export interface sidebarGetAlbumShares {
|
|||
* 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: sidebarGetAlbumShares_album
|
||||
album: sidebarGetAlbumShares_album;
|
||||
}
|
||||
|
||||
export interface sidebarGetAlbumSharesVariables {
|
||||
id: string
|
||||
id: string;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebarGetPhotoShares_media_shares {
|
||||
__typename: 'ShareToken'
|
||||
id: string
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
id: string;
|
||||
token: string;
|
||||
/**
|
||||
* Whether or not a password is needed to access the share
|
||||
*/
|
||||
hasPassword: boolean
|
||||
hasPassword: boolean;
|
||||
}
|
||||
|
||||
export interface sidebarGetPhotoShares_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
shares: sidebarGetPhotoShares_media_shares[]
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
shares: sidebarGetPhotoShares_media_shares[];
|
||||
}
|
||||
|
||||
export interface sidebarGetPhotoShares {
|
||||
|
@ -28,9 +28,9 @@ export interface sidebarGetPhotoShares {
|
|||
* Get media by id, user must own the media or be admin.
|
||||
* If valid tokenCredentials are provided, the media may be retrived without further authentication
|
||||
*/
|
||||
media: sidebarGetPhotoShares_media
|
||||
media: sidebarGetPhotoShares_media;
|
||||
}
|
||||
|
||||
export interface sidebarGetPhotoSharesVariables {
|
||||
id: string
|
||||
id: string;
|
||||
}
|
||||
|
|
|
@ -3,155 +3,155 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MediaType } from './../../../__generated__/globalTypes'
|
||||
import { MediaType } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: sidebarPhoto
|
||||
// ====================================================
|
||||
|
||||
export interface sidebarPhoto_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 sidebarPhoto_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 sidebarPhoto_media_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 sidebarPhoto_media_videoMetadata {
|
||||
__typename: 'VideoMetadata'
|
||||
id: string
|
||||
width: number
|
||||
height: number
|
||||
duration: number
|
||||
codec: string | null
|
||||
framerate: number | null
|
||||
bitrate: string | null
|
||||
colorProfile: string | null
|
||||
audio: string | null
|
||||
__typename: "VideoMetadata";
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
duration: number;
|
||||
codec: string | null;
|
||||
framerate: number | null;
|
||||
bitrate: string | null;
|
||||
colorProfile: string | null;
|
||||
audio: string | null;
|
||||
}
|
||||
|
||||
export interface sidebarPhoto_media_exif {
|
||||
__typename: 'MediaEXIF'
|
||||
id: string
|
||||
__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;
|
||||
}
|
||||
|
||||
export interface sidebarPhoto_media_faces_rectangle {
|
||||
__typename: 'FaceRectangle'
|
||||
minX: number
|
||||
maxX: number
|
||||
minY: number
|
||||
maxY: number
|
||||
__typename: "FaceRectangle";
|
||||
minX: number;
|
||||
maxX: number;
|
||||
minY: number;
|
||||
maxY: number;
|
||||
}
|
||||
|
||||
export interface sidebarPhoto_media_faces_faceGroup {
|
||||
__typename: 'FaceGroup'
|
||||
id: string
|
||||
__typename: "FaceGroup";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface sidebarPhoto_media_faces {
|
||||
__typename: 'ImageFace'
|
||||
id: string
|
||||
rectangle: sidebarPhoto_media_faces_rectangle
|
||||
faceGroup: sidebarPhoto_media_faces_faceGroup
|
||||
__typename: "ImageFace";
|
||||
id: string;
|
||||
rectangle: sidebarPhoto_media_faces_rectangle;
|
||||
faceGroup: sidebarPhoto_media_faces_faceGroup;
|
||||
}
|
||||
|
||||
export interface sidebarPhoto_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
title: string
|
||||
type: MediaType
|
||||
__typename: "Media";
|
||||
id: string;
|
||||
title: string;
|
||||
type: MediaType;
|
||||
/**
|
||||
* URL to display the photo in full resolution, will be null for videos
|
||||
*/
|
||||
highRes: sidebarPhoto_media_highRes | null
|
||||
highRes: sidebarPhoto_media_highRes | null;
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: sidebarPhoto_media_thumbnail | null
|
||||
thumbnail: sidebarPhoto_media_thumbnail | null;
|
||||
/**
|
||||
* URL to get the video in a web format that can be played in the browser, will be null for photos
|
||||
*/
|
||||
videoWeb: sidebarPhoto_media_videoWeb | null
|
||||
videoMetadata: sidebarPhoto_media_videoMetadata | null
|
||||
exif: sidebarPhoto_media_exif | null
|
||||
faces: sidebarPhoto_media_faces[]
|
||||
videoWeb: sidebarPhoto_media_videoWeb | null;
|
||||
videoMetadata: sidebarPhoto_media_videoMetadata | null;
|
||||
exif: sidebarPhoto_media_exif | null;
|
||||
faces: sidebarPhoto_media_faces[];
|
||||
}
|
||||
|
||||
export interface sidebarPhoto {
|
||||
|
@ -159,9 +159,9 @@ export interface sidebarPhoto {
|
|||
* Get media by id, user must own the media or be admin.
|
||||
* If valid tokenCredentials are provided, the media may be retrived without further authentication
|
||||
*/
|
||||
media: sidebarPhoto_media
|
||||
media: sidebarPhoto_media;
|
||||
}
|
||||
|
||||
export interface sidebarPhotoVariables {
|
||||
id: string
|
||||
id: string;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebarPhotoAddShare_shareMedia {
|
||||
__typename: 'ShareToken'
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface sidebarPhotoAddShare {
|
||||
/**
|
||||
* Generate share token for media
|
||||
*/
|
||||
shareMedia: sidebarPhotoAddShare_shareMedia
|
||||
shareMedia: sidebarPhotoAddShare_shareMedia;
|
||||
}
|
||||
|
||||
export interface sidebarPhotoAddShareVariables {
|
||||
id: string
|
||||
password?: string | null
|
||||
expire?: any | null
|
||||
id: string;
|
||||
password?: string | null;
|
||||
expire?: any | null;
|
||||
}
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebarProtectShare_protectShareToken {
|
||||
__typename: 'ShareToken'
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
token: string;
|
||||
/**
|
||||
* Whether or not a password is needed to access the share
|
||||
*/
|
||||
hasPassword: boolean
|
||||
hasPassword: boolean;
|
||||
}
|
||||
|
||||
export interface sidebarProtectShare {
|
||||
/**
|
||||
* Set a password for a token, if null is passed for the password argument, the password will be cleared
|
||||
*/
|
||||
protectShareToken: sidebarProtectShare_protectShareToken
|
||||
protectShareToken: sidebarProtectShare_protectShareToken;
|
||||
}
|
||||
|
||||
export interface sidebarProtectShareVariables {
|
||||
token: string
|
||||
password?: string | null
|
||||
token: string;
|
||||
password?: string | null;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
// ====================================================
|
||||
|
||||
export interface sidebareDeleteShare_deleteShareToken {
|
||||
__typename: 'ShareToken'
|
||||
token: string
|
||||
__typename: "ShareToken";
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface sidebareDeleteShare {
|
||||
/**
|
||||
* Delete a share token by it's token value
|
||||
*/
|
||||
deleteShareToken: sidebareDeleteShare_deleteShareToken
|
||||
deleteShareToken: sidebareDeleteShare_deleteShareToken;
|
||||
}
|
||||
|
||||
export interface sidebareDeleteShareVariables {
|
||||
token: string
|
||||
token: string;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { useQuery } from '@apollo/client'
|
||||
import gql from 'graphql-tag'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Dropdown, { DropdownItem } from '../../primitives/form/Dropdown'
|
||||
import { FavoriteCheckboxProps, FavoritesCheckbox } from '../album/AlbumFilter'
|
||||
|
||||
import { ReactComponent as DateIcon } from './icons/date.svg'
|
||||
import { earliestMedia } from './__generated__/earliestMedia'
|
||||
|
||||
const EARLIEST_MEDIA_QUERY = gql`
|
||||
query earliestMedia {
|
||||
myMedia(
|
||||
order: { order_by: "date_shot", order_direction: ASC }
|
||||
paginate: { limit: 1 }
|
||||
) {
|
||||
id
|
||||
date
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type DateSelectorProps = {
|
||||
filterDate: string | null
|
||||
setFilterDate(date: string | null): void
|
||||
}
|
||||
|
||||
const DateSelector = ({ filterDate, setFilterDate }: DateSelectorProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { data, loading } = useQuery<earliestMedia>(EARLIEST_MEDIA_QUERY)
|
||||
|
||||
let items: DropdownItem[] = [
|
||||
{
|
||||
value: 'all',
|
||||
label: t('timeline_filter.date.dropdown_all', 'From today'),
|
||||
},
|
||||
]
|
||||
|
||||
if (data) {
|
||||
const dateStr = data.myMedia[0].date
|
||||
const date = new Date(dateStr)
|
||||
const now = new Date()
|
||||
|
||||
const currentYear = now.getFullYear()
|
||||
const earliestYear = date.getFullYear()
|
||||
|
||||
const years: number[] = []
|
||||
for (let i = currentYear - 1; i >= earliestYear; i--) {
|
||||
years.push(i)
|
||||
}
|
||||
|
||||
const yearItems = years.map<DropdownItem>(x => ({
|
||||
value: `${x}`,
|
||||
label: `${x} and earlier`,
|
||||
}))
|
||||
items = [...items, ...yearItems]
|
||||
}
|
||||
|
||||
return (
|
||||
<fieldset>
|
||||
<legend id="filter_group_date-label" className="inline-block mb-1">
|
||||
<DateIcon
|
||||
className="inline-block align-baseline mr-1"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{t('timeline_filter.date.label', 'Date')}</span>
|
||||
</legend>
|
||||
<div>
|
||||
<Dropdown
|
||||
aria-labelledby="filter_group_date-label"
|
||||
setSelected={date =>
|
||||
date == 'all' ? setFilterDate(null) : setFilterDate(date)
|
||||
}
|
||||
value={filterDate || 'all'}
|
||||
items={items}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
type TimelineFiltersProps = DateSelectorProps & FavoriteCheckboxProps
|
||||
|
||||
const TimelineFilters = ({
|
||||
onlyFavorites,
|
||||
setOnlyFavorites,
|
||||
filterDate,
|
||||
setFilterDate,
|
||||
}: TimelineFiltersProps) => {
|
||||
return (
|
||||
<div className="flex items-end gap-4 flex-wrap mb-4">
|
||||
<DateSelector filterDate={filterDate} setFilterDate={setFilterDate} />
|
||||
<FavoritesCheckbox
|
||||
onlyFavorites={onlyFavorites}
|
||||
setOnlyFavorites={setOnlyFavorites}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TimelineFilters
|
|
@ -0,0 +1,39 @@
|
|||
import { MockedProvider } from '@apollo/client/testing'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import React from 'react'
|
||||
import { MemoryRouter } from 'react-router-dom'
|
||||
import TimelineGallery, { MY_TIMELINE_QUERY } from './TimelineGallery'
|
||||
import { timelineData } from './timelineTestData'
|
||||
|
||||
jest.mock('../../hooks/useScrollPagination')
|
||||
|
||||
test('timeline with media', async () => {
|
||||
const graphqlMocks = [
|
||||
{
|
||||
request: {
|
||||
query: MY_TIMELINE_QUERY,
|
||||
variables: { onlyFavorites: false, offset: 0, limit: 200 },
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
myTimeline: timelineData,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/timeline']}>
|
||||
<MockedProvider mocks={graphqlMocks}>
|
||||
<TimelineGallery />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
)
|
||||
|
||||
expect(screen.queryByLabelText('Show only favorites')).toBeInTheDocument()
|
||||
|
||||
expect(await screen.findAllByRole('link')).toHaveLength(4)
|
||||
expect(await screen.findAllByRole('img')).toHaveLength(5)
|
||||
|
||||
screen.debug()
|
||||
})
|
|
@ -4,7 +4,6 @@ import { useQuery, gql } from '@apollo/client'
|
|||
import TimelineGroupDate from './TimelineGroupDate'
|
||||
import PresentView from '../photoGallery/presentView/PresentView'
|
||||
import useURLParameters from '../../hooks/useURLParameters'
|
||||
import { FavoritesCheckbox } from '../album/AlbumFilter'
|
||||
import useScrollPagination from '../../hooks/useScrollPagination'
|
||||
import PaginateLoader from '../PaginateLoader'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
@ -20,37 +19,42 @@ import {
|
|||
import MediaSidebar from '../sidebar/MediaSidebar'
|
||||
import { SidebarContext } from '../sidebar/Sidebar'
|
||||
import { urlPresentModeSetupHook } from '../photoGallery/photoGalleryReducer'
|
||||
import TimelineFilters from './TimelineFilters'
|
||||
import client from '../../apolloClient'
|
||||
|
||||
const MY_TIMELINE_QUERY = gql`
|
||||
query myTimeline($onlyFavorites: Boolean, $limit: Int, $offset: Int) {
|
||||
export const MY_TIMELINE_QUERY = gql`
|
||||
query myTimeline(
|
||||
$onlyFavorites: Boolean
|
||||
$limit: Int
|
||||
$offset: Int
|
||||
$fromDate: Time
|
||||
) {
|
||||
myTimeline(
|
||||
onlyFavorites: $onlyFavorites
|
||||
fromDate: $fromDate
|
||||
paginate: { limit: $limit, offset: $offset }
|
||||
) {
|
||||
id
|
||||
title
|
||||
type
|
||||
thumbnail {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
highRes {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
videoWeb {
|
||||
url
|
||||
}
|
||||
favorite
|
||||
album {
|
||||
id
|
||||
title
|
||||
}
|
||||
media {
|
||||
id
|
||||
title
|
||||
type
|
||||
thumbnail {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
highRes {
|
||||
url
|
||||
width
|
||||
height
|
||||
}
|
||||
videoWeb {
|
||||
url
|
||||
}
|
||||
favorite
|
||||
}
|
||||
mediaTotal
|
||||
date
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +67,13 @@ export type TimelineActiveIndex = {
|
|||
|
||||
export type TimelineGroup = {
|
||||
date: string
|
||||
groups: myTimeline_myTimeline[]
|
||||
albums: TimelineGroupAlbum[]
|
||||
}
|
||||
|
||||
export type TimelineGroupAlbum = {
|
||||
id: string
|
||||
title: string
|
||||
media: myTimeline_myTimeline[]
|
||||
}
|
||||
|
||||
const TimelineGallery = () => {
|
||||
|
@ -74,7 +84,10 @@ const TimelineGallery = () => {
|
|||
|
||||
const onlyFavorites = getParam('favorites') == '1' ? true : false
|
||||
const setOnlyFavorites = (favorites: boolean) =>
|
||||
setParam('favorites', favorites ? '1' : '0')
|
||||
setParam('favorites', favorites ? '1' : null)
|
||||
|
||||
const filterDate = getParam('date')
|
||||
const setFilterDate = (x: string) => setParam('date', x)
|
||||
|
||||
const favoritesNeedsRefresh = useRef(false)
|
||||
|
||||
|
@ -94,8 +107,11 @@ const TimelineGallery = () => {
|
|||
>(MY_TIMELINE_QUERY, {
|
||||
variables: {
|
||||
onlyFavorites,
|
||||
fromDate: filterDate
|
||||
? `${parseInt(filterDate) + 1}-01-01T00:00:00Z`
|
||||
: undefined,
|
||||
offset: 0,
|
||||
limit: 50,
|
||||
limit: 200,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -123,6 +139,20 @@ const TimelineGallery = () => {
|
|||
}
|
||||
}, [mediaState.activeIndex])
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
await client.resetStore()
|
||||
await refetch({
|
||||
onlyFavorites,
|
||||
fromDate: filterDate
|
||||
? `${parseInt(filterDate) + 1}-01-01T00:00:00Z`
|
||||
: undefined,
|
||||
offset: 0,
|
||||
limit: 200,
|
||||
})
|
||||
})()
|
||||
}, [filterDate])
|
||||
|
||||
urlPresentModeSetupHook({
|
||||
dispatchMedia,
|
||||
openPresentMode: event => {
|
||||
|
@ -155,12 +185,12 @@ const TimelineGallery = () => {
|
|||
|
||||
return (
|
||||
<div className="overflow-x-hidden">
|
||||
<div className="mb-2">
|
||||
<FavoritesCheckbox
|
||||
onlyFavorites={onlyFavorites}
|
||||
setOnlyFavorites={setOnlyFavorites}
|
||||
/>
|
||||
</div>
|
||||
<TimelineFilters
|
||||
onlyFavorites={onlyFavorites}
|
||||
setOnlyFavorites={setOnlyFavorites}
|
||||
filterDate={filterDate}
|
||||
setFilterDate={setFilterDate}
|
||||
/>
|
||||
<div className="-mx-3 flex flex-wrap" ref={containerElem}>
|
||||
{timelineGroups}
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import styled from 'styled-components'
|
||||
import { MediaThumbnail } from '../photoGallery/MediaThumbnail'
|
||||
import { PhotoFiller } from '../photoGallery/PhotoGallery'
|
||||
import {
|
||||
toggleFavoriteAction,
|
||||
useMarkFavoriteMutation,
|
||||
|
@ -13,20 +13,6 @@ import {
|
|||
TimelineGalleryState,
|
||||
} from './timelineGalleryReducer'
|
||||
|
||||
const TotalItemsBubble = styled(Link)`
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 6px;
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
padding: 8px 0;
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
|
||||
color: black;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
`
|
||||
|
||||
type TimelineGroupAlbumProps = {
|
||||
dateIndex: number
|
||||
albumIndex: number
|
||||
|
@ -40,8 +26,11 @@ const TimelineGroupAlbum = ({
|
|||
mediaState,
|
||||
dispatchMedia,
|
||||
}: TimelineGroupAlbumProps) => {
|
||||
const { media, mediaTotal, album } =
|
||||
mediaState.timelineGroups[dateIndex].groups[albumIndex]
|
||||
const {
|
||||
media,
|
||||
title: albumTitle,
|
||||
id: albumID,
|
||||
} = mediaState.timelineGroups[dateIndex].albums[albumIndex]
|
||||
|
||||
const [markFavorite] = useMarkFavoriteMutation()
|
||||
|
||||
|
@ -79,24 +68,14 @@ const TimelineGroupAlbum = ({
|
|||
/>
|
||||
))
|
||||
|
||||
let itemsBubble = null
|
||||
const mediaVisibleCount = media.length
|
||||
if (mediaTotal > mediaVisibleCount) {
|
||||
itemsBubble = (
|
||||
<TotalItemsBubble to={`/album/${album.id}`}>
|
||||
{`+${Math.min(mediaTotal - mediaVisibleCount, 99)}`}
|
||||
</TotalItemsBubble>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-2">
|
||||
<Link to={`/album/${album.id}`} className="hover:underline">
|
||||
{album.title}
|
||||
<Link to={`/album/${albumID}`} className="hover:underline">
|
||||
{albumTitle}
|
||||
</Link>
|
||||
<div className="flex flex-wrap items-center h-[210px] relative -mx-1 pr-4 overflow-hidden">
|
||||
<div className="flex flex-wrap items-center relative -mx-1 overflow-hidden">
|
||||
{mediaElms}
|
||||
{itemsBubble}
|
||||
<PhotoFiller />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -27,9 +27,9 @@ const TimelineGroupDate = ({
|
|||
|
||||
const group = mediaState.timelineGroups[groupIndex]
|
||||
|
||||
const albumGroupElms = group.groups.map((group, i) => (
|
||||
const albumGroupElms = group.albums.map((album, i) => (
|
||||
<TimelineGroupAlbum
|
||||
key={`${group.date}_${group.album.id}`}
|
||||
key={`${group.date}_${album.id}`}
|
||||
dateIndex={groupIndex}
|
||||
albumIndex={i}
|
||||
mediaState={mediaState}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: earliestMedia
|
||||
// ====================================================
|
||||
|
||||
export interface earliestMedia_myMedia {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
/**
|
||||
* The date the image was shot or the date it was imported as a fallback
|
||||
*/
|
||||
date: any
|
||||
}
|
||||
|
||||
export interface earliestMedia {
|
||||
/**
|
||||
* List of media owned by the logged in user
|
||||
*/
|
||||
myMedia: earliestMedia_myMedia[]
|
||||
}
|
|
@ -9,53 +9,53 @@ import { MediaType } from './../../../__generated__/globalTypes'
|
|||
// GraphQL query operation: myTimeline
|
||||
// ====================================================
|
||||
|
||||
export interface myTimeline_myTimeline_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Width of the image in pixels
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* Height of the image in pixels
|
||||
*/
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_highRes {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Width of the image in pixels
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* Height of the image in pixels
|
||||
*/
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_videoWeb {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_album {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_media_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Width of the image in pixels
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* Height of the image in pixels
|
||||
*/
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_media_highRes {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Width of the image in pixels
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* Height of the image in pixels
|
||||
*/
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_media_videoWeb {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline_media {
|
||||
export interface myTimeline_myTimeline {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
title: string
|
||||
|
@ -63,27 +63,30 @@ export interface myTimeline_myTimeline_media {
|
|||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: myTimeline_myTimeline_media_thumbnail | null
|
||||
thumbnail: myTimeline_myTimeline_thumbnail | null
|
||||
/**
|
||||
* URL to display the photo in full resolution, will be null for videos
|
||||
*/
|
||||
highRes: myTimeline_myTimeline_media_highRes | null
|
||||
highRes: myTimeline_myTimeline_highRes | null
|
||||
/**
|
||||
* URL to get the video in a web format that can be played in the browser, will be null for photos
|
||||
*/
|
||||
videoWeb: myTimeline_myTimeline_media_videoWeb | null
|
||||
videoWeb: myTimeline_myTimeline_videoWeb | null
|
||||
favorite: boolean
|
||||
}
|
||||
|
||||
export interface myTimeline_myTimeline {
|
||||
__typename: 'TimelineGroup'
|
||||
/**
|
||||
* The album that holds the media
|
||||
*/
|
||||
album: myTimeline_myTimeline_album
|
||||
media: myTimeline_myTimeline_media[]
|
||||
mediaTotal: number
|
||||
/**
|
||||
* The date the image was shot or the date it was imported as a fallback
|
||||
*/
|
||||
date: any
|
||||
}
|
||||
|
||||
export interface myTimeline {
|
||||
/**
|
||||
* Get a list of media, ordered first by day, then by album if multiple media was found for the same day.
|
||||
*/
|
||||
myTimeline: myTimeline_myTimeline[]
|
||||
}
|
||||
|
||||
|
@ -91,4 +94,5 @@ export interface myTimelineVariables {
|
|||
onlyFavorites?: boolean | null
|
||||
limit?: number | null
|
||||
offset?: number | null
|
||||
fromDate?: any | null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="13px" height="15px" viewBox="0 0 13 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M9.16666667,5.68434189e-14 C9.41979718,5.68434189e-14 9.62899397,0.188102588 9.66210226,0.432152962 L9.66666667,0.5 L9.666,1.333 L11.1666667,1.33333333 C12.1285626,1.33333333 12.9174396,2.07411552 12.9939226,3.01630483 L13,3.16666667 L13,12.5 C13,13.512522 12.1791887,14.3333333 11.1666667,14.3333333 L11.1666667,14.3333333 L1.83333333,14.3333333 C0.820811292,14.3333333 0,13.512522 0,12.5 L0,12.5 L0,3.16666667 C0,2.15414463 0.820811292,1.33333333 1.83333333,1.33333333 L1.83333333,1.33333333 L3.333,1.333 L3.33333333,0.5 C3.33333333,0.223857625 3.55719096,5.68434189e-14 3.83333333,5.68434189e-14 C4.08646384,5.68434189e-14 4.29566064,0.188102588 4.32876892,0.432152962 L4.33333333,0.5 L4.333,1.333 L8.666,1.333 L8.66666667,0.5 C8.66666667,0.223857625 8.89052429,5.68434189e-14 9.16666667,5.68434189e-14 Z M12,6.333 L1,6.333 L1,12.5 C1,12.9248344 1.31790432,13.2754183 1.72880177,13.3268405 L1.83333333,13.3333333 L11.1666667,13.3333333 C11.626904,13.3333333 12,12.9602373 12,12.5 L12,12.5 L12,6.333 Z M3.333,2.333 L1.83333333,2.33333333 C1.37309604,2.33333333 1,2.70642938 1,3.16666667 L1,3.16666667 L1,5.333 L12,5.333 L12,3.16666667 C12,2.74183224 11.6820957,2.39124835 11.2711982,2.33982618 L11.1666667,2.33333333 L9.666,2.333 L9.66666667,3.16666667 C9.66666667,3.44280904 9.44280904,3.66666667 9.16666667,3.66666667 C8.91353616,3.66666667 8.70433936,3.47856408 8.67123108,3.2345137 L8.66666667,3.16666667 L8.666,2.333 L4.333,2.333 L4.33333333,3.16666667 C4.33333333,3.44280904 4.10947571,3.66666667 3.83333333,3.66666667 C3.58020282,3.66666667 3.37100603,3.47856408 3.33789774,3.2345137 L3.33333333,3.16666667 L3.333,2.333 Z" fill="currentColor" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -1,10 +1,10 @@
|
|||
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
||||
import { MediaType } from '../../__generated__/globalTypes'
|
||||
import {
|
||||
timelineGalleryReducer,
|
||||
TimelineGalleryState,
|
||||
TimelineMediaIndex,
|
||||
} from './timelineGalleryReducer'
|
||||
import { timelineData } from './timelineTestData'
|
||||
|
||||
describe('timeline gallery reducer', () => {
|
||||
const defaultEmptyState: TimelineGalleryState = {
|
||||
|
@ -17,125 +17,6 @@ describe('timeline gallery reducer', () => {
|
|||
timelineGroups: [],
|
||||
}
|
||||
|
||||
const timelineData: myTimeline_myTimeline[] = [
|
||||
{
|
||||
album: {
|
||||
id: '5',
|
||||
title: 'first album',
|
||||
__typename: 'Album',
|
||||
},
|
||||
media: [
|
||||
{
|
||||
id: '165',
|
||||
title: '3666760020.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
url: 'http://localhost:4001/photo/thumbnail_3666760020_jpg_x76GG5pS.jpg',
|
||||
width: 768,
|
||||
height: 1024,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
highRes: {
|
||||
url: 'http://localhost:4001/photo/3666760020_wijGDNZ2.jpg',
|
||||
width: 3024,
|
||||
height: 4032,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
__typename: 'Media',
|
||||
},
|
||||
{
|
||||
id: '184',
|
||||
title: '7414455077.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
url: 'http://localhost:4001/photo/thumbnail_7414455077_jpg_9JYHHYh6.jpg',
|
||||
width: 768,
|
||||
height: 1024,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
highRes: {
|
||||
url: 'http://localhost:4001/photo/7414455077_0ejDBiKr.jpg',
|
||||
width: 3024,
|
||||
height: 4032,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
__typename: 'Media',
|
||||
},
|
||||
],
|
||||
mediaTotal: 5,
|
||||
date: '2019-09-21T00:00:00Z',
|
||||
__typename: 'TimelineGroup',
|
||||
},
|
||||
{
|
||||
album: {
|
||||
id: '5',
|
||||
title: 'another album',
|
||||
__typename: 'Album',
|
||||
},
|
||||
media: [
|
||||
{
|
||||
id: '165',
|
||||
title: '3666760020.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
url: 'http://localhost:4001/photo/thumbnail_3666760020_jpg_x76GG5pS.jpg',
|
||||
width: 768,
|
||||
height: 1024,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
highRes: {
|
||||
url: 'http://localhost:4001/photo/3666760020_wijGDNZ2.jpg',
|
||||
width: 3024,
|
||||
height: 4032,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
__typename: 'Media',
|
||||
},
|
||||
],
|
||||
mediaTotal: 7,
|
||||
date: '2019-09-21T00:00:00Z',
|
||||
__typename: 'TimelineGroup',
|
||||
},
|
||||
{
|
||||
__typename: 'TimelineGroup',
|
||||
album: {
|
||||
__typename: 'Album',
|
||||
id: '5',
|
||||
title: 'album on another day',
|
||||
},
|
||||
date: '2019-09-13T00:00:00Z',
|
||||
mediaTotal: 1,
|
||||
media: [
|
||||
{
|
||||
__typename: 'Media',
|
||||
favorite: false,
|
||||
videoWeb: null,
|
||||
thumbnail: {
|
||||
url: 'http://localhost:4001/photo/thumbnail_3666760020_jpg_x76GG5pS.jpg',
|
||||
width: 768,
|
||||
height: 1024,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
highRes: {
|
||||
url: 'http://localhost:4001/photo/3666760020_wijGDNZ2.jpg',
|
||||
width: 3024,
|
||||
height: 4032,
|
||||
__typename: 'MediaURL',
|
||||
},
|
||||
id: '321',
|
||||
title: 'asdfimg.jpg',
|
||||
type: MediaType.Photo,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const defaultState = timelineGalleryReducer(defaultEmptyState, {
|
||||
type: 'replaceTimelineGroups',
|
||||
timeline: timelineData,
|
||||
|
@ -151,68 +32,167 @@ describe('timeline gallery reducer', () => {
|
|||
},
|
||||
timelineGroups: [
|
||||
{
|
||||
date: '2019-09-21T00:00:00Z',
|
||||
groups: [
|
||||
date: '2020-12-13T00:00:00Z',
|
||||
albums: [
|
||||
{
|
||||
album: {
|
||||
id: '5',
|
||||
title: 'first album',
|
||||
},
|
||||
date: '2019-09-21T00:00:00Z',
|
||||
id: '522',
|
||||
media: [
|
||||
{
|
||||
__typename: 'Media',
|
||||
album: {
|
||||
__typename: 'Album',
|
||||
id: '522',
|
||||
title: 'random',
|
||||
},
|
||||
date: '2020-12-13T18:03:40Z',
|
||||
favorite: false,
|
||||
highRes: {},
|
||||
id: '165',
|
||||
thumbnail: {},
|
||||
title: '3666760020.jpg',
|
||||
type: 'Photo',
|
||||
},
|
||||
{
|
||||
highRes: {},
|
||||
id: '184',
|
||||
thumbnail: {},
|
||||
title: '7414455077.jpg',
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
height: 4480,
|
||||
url: 'http://localhost:4001/photo/122A2876_5cSPMiKL.jpg',
|
||||
width: 6720,
|
||||
},
|
||||
id: '1058',
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
height: 682,
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2876_jpg_Kp1U80vD.jpg',
|
||||
width: 1024,
|
||||
},
|
||||
title: '122A2876.jpg',
|
||||
type: 'Photo',
|
||||
videoWeb: null,
|
||||
},
|
||||
],
|
||||
mediaTotal: 5,
|
||||
},
|
||||
{
|
||||
album: {
|
||||
id: '5',
|
||||
title: 'another album',
|
||||
},
|
||||
date: '2019-09-21T00:00:00Z',
|
||||
media: [
|
||||
{
|
||||
id: '165',
|
||||
},
|
||||
],
|
||||
mediaTotal: 7,
|
||||
title: 'random',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2019-09-13T00:00:00Z',
|
||||
groups: [
|
||||
date: '2020-11-25T00:00:00Z',
|
||||
albums: [
|
||||
{
|
||||
album: {
|
||||
id: '5',
|
||||
title: 'album on another day',
|
||||
},
|
||||
date: '2019-09-13T00:00:00Z',
|
||||
id: '523',
|
||||
title: 'another_album',
|
||||
media: [
|
||||
{
|
||||
__typename: 'Media',
|
||||
album: {
|
||||
__typename: 'Album',
|
||||
id: '523',
|
||||
title: 'another_album',
|
||||
},
|
||||
date: '2020-11-25T16:14:33Z',
|
||||
favorite: false,
|
||||
highRes: {},
|
||||
id: '321',
|
||||
thumbnail: {},
|
||||
title: 'asdfimg.jpg',
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
height: 4118,
|
||||
url: 'http://localhost:4001/photo/122A2630-Edit_ySQWFAgE.jpg',
|
||||
width: 6177,
|
||||
},
|
||||
id: '1059',
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
height: 682,
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2630-Edit_jpg_pwjtMkpy.jpg',
|
||||
width: 1024,
|
||||
},
|
||||
title: '122A2630-Edit.jpg',
|
||||
type: 'Photo',
|
||||
videoWeb: null,
|
||||
},
|
||||
{
|
||||
__typename: 'Media',
|
||||
album: {
|
||||
__typename: 'Album',
|
||||
id: '523',
|
||||
title: 'another_album',
|
||||
},
|
||||
date: '2020-11-25T16:43:59Z',
|
||||
favorite: false,
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
height: 884,
|
||||
url: 'http://localhost:4001/photo/122A2785-2_mCnWjLdb.jpg',
|
||||
width: 884,
|
||||
},
|
||||
id: '1060',
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
height: 1024,
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2785-2_jpg_CevmxEXf.jpg',
|
||||
width: 1024,
|
||||
},
|
||||
title: '122A2785-2.jpg',
|
||||
type: 'Photo',
|
||||
videoWeb: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '522',
|
||||
title: 'random',
|
||||
media: [
|
||||
{
|
||||
__typename: 'Media',
|
||||
album: {
|
||||
__typename: 'Album',
|
||||
id: '522',
|
||||
title: 'random',
|
||||
},
|
||||
date: '2020-11-25T16:14:33Z',
|
||||
favorite: false,
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
height: 4118,
|
||||
url: 'http://localhost:4001/photo/122A2630-Edit_em9g89qg.jpg',
|
||||
width: 6177,
|
||||
},
|
||||
id: '1056',
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
height: 682,
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2630-Edit_jpg_aJPCSDDl.jpg',
|
||||
width: 1024,
|
||||
},
|
||||
title: '122A2630-Edit.jpg',
|
||||
type: 'Photo',
|
||||
videoWeb: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2020-11-09T00:00:00Z',
|
||||
albums: [
|
||||
{
|
||||
id: '522',
|
||||
title: 'random',
|
||||
media: [
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1054',
|
||||
title: '122A2559.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2559_jpg_MsOJtPi8.jpg',
|
||||
width: 1024,
|
||||
height: 712,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2559_FDsQHuBN.jpg',
|
||||
width: 6246,
|
||||
height: 4346,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '522', title: 'random' },
|
||||
date: '2020-11-09T15:38:09Z',
|
||||
},
|
||||
],
|
||||
mediaTotal: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -267,20 +247,20 @@ describe('timeline gallery reducer', () => {
|
|||
media: 0,
|
||||
},
|
||||
out: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 0,
|
||||
media: 1,
|
||||
media: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'next album',
|
||||
in: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 0,
|
||||
media: 1,
|
||||
},
|
||||
out: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 1,
|
||||
media: 0,
|
||||
},
|
||||
|
@ -288,12 +268,12 @@ describe('timeline gallery reducer', () => {
|
|||
{
|
||||
name: 'next date',
|
||||
in: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 1,
|
||||
media: 1,
|
||||
media: 0,
|
||||
},
|
||||
out: {
|
||||
date: 1,
|
||||
date: 2,
|
||||
album: 0,
|
||||
media: 0,
|
||||
},
|
||||
|
@ -301,12 +281,12 @@ describe('timeline gallery reducer', () => {
|
|||
{
|
||||
name: 'reached end',
|
||||
in: {
|
||||
date: 1,
|
||||
date: 2,
|
||||
album: 0,
|
||||
media: 0,
|
||||
},
|
||||
out: {
|
||||
date: 1,
|
||||
date: 2,
|
||||
album: 0,
|
||||
media: 0,
|
||||
},
|
||||
|
@ -366,12 +346,12 @@ describe('timeline gallery reducer', () => {
|
|||
{
|
||||
name: 'previous album',
|
||||
in: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 1,
|
||||
media: 0,
|
||||
},
|
||||
out: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 0,
|
||||
media: 1,
|
||||
},
|
||||
|
@ -379,12 +359,12 @@ describe('timeline gallery reducer', () => {
|
|||
{
|
||||
name: 'previous date',
|
||||
in: {
|
||||
date: 1,
|
||||
date: 2,
|
||||
album: 0,
|
||||
media: 0,
|
||||
},
|
||||
out: {
|
||||
date: 0,
|
||||
date: 1,
|
||||
album: 1,
|
||||
media: 0,
|
||||
},
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
myTimeline_myTimeline,
|
||||
myTimeline_myTimeline_media,
|
||||
} from './__generated__/myTimeline'
|
||||
import { TimelineGroup } from './TimelineGallery'
|
||||
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
||||
import { TimelineGroup, TimelineGroupAlbum } from './TimelineGallery'
|
||||
import { GalleryAction } from '../photoGallery/photoGalleryReducer'
|
||||
import { isNil } from '../../helpers/utils'
|
||||
|
||||
export interface TimelineMediaIndex {
|
||||
date: number
|
||||
|
@ -30,18 +28,7 @@ export function timelineGalleryReducer(
|
|||
): TimelineGalleryState {
|
||||
switch (action.type) {
|
||||
case 'replaceTimelineGroups': {
|
||||
const dateGroupedAlbums = action.timeline.reduce((acc, val) => {
|
||||
if (acc.length == 0 || acc[acc.length - 1].date != val.date) {
|
||||
acc.push({
|
||||
date: val.date,
|
||||
groups: [val],
|
||||
})
|
||||
} else {
|
||||
acc[acc.length - 1].groups.push(val)
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [] as TimelineGroup[])
|
||||
const timelineGroups = convertMediaToTimelineGroups(action.timeline)
|
||||
|
||||
return {
|
||||
...state,
|
||||
|
@ -50,7 +37,7 @@ export function timelineGalleryReducer(
|
|||
date: -1,
|
||||
media: -1,
|
||||
},
|
||||
timelineGroups: dateGroupedAlbums,
|
||||
timelineGroups,
|
||||
}
|
||||
}
|
||||
case 'nextImage': {
|
||||
|
@ -64,7 +51,7 @@ export function timelineGalleryReducer(
|
|||
return state
|
||||
}
|
||||
|
||||
const albumGroups = timelineGroups[activeIndex.date].groups
|
||||
const albumGroups = timelineGroups[activeIndex.date].albums
|
||||
const albumMedia = albumGroups[activeIndex.album].media
|
||||
|
||||
if (activeIndex.media < albumMedia.length - 1) {
|
||||
|
@ -124,7 +111,7 @@ export function timelineGalleryReducer(
|
|||
}
|
||||
|
||||
if (activeIndex.album > 0) {
|
||||
const albumGroups = state.timelineGroups[activeIndex.date].groups
|
||||
const albumGroups = state.timelineGroups[activeIndex.date].albums
|
||||
const albumMedia = albumGroups[activeIndex.album - 1].media
|
||||
|
||||
return {
|
||||
|
@ -138,7 +125,7 @@ export function timelineGalleryReducer(
|
|||
}
|
||||
|
||||
if (activeIndex.date > 0) {
|
||||
const albumGroups = state.timelineGroups[activeIndex.date - 1].groups
|
||||
const albumGroups = state.timelineGroups[activeIndex.date - 1].albums
|
||||
const albumMedia = albumGroups[albumGroups.length - 1].media
|
||||
|
||||
return {
|
||||
|
@ -181,9 +168,9 @@ export const getTimelineImage = ({
|
|||
}: {
|
||||
mediaState: TimelineGalleryState
|
||||
index: TimelineMediaIndex
|
||||
}): myTimeline_myTimeline_media => {
|
||||
}): myTimeline_myTimeline => {
|
||||
const { date, album, media } = index
|
||||
return mediaState.timelineGroups[date].groups[album].media[media]
|
||||
return mediaState.timelineGroups[date].albums[album].media[media]
|
||||
}
|
||||
|
||||
export const getActiveTimelineImage = ({
|
||||
|
@ -203,6 +190,74 @@ export const getActiveTimelineImage = ({
|
|||
return getTimelineImage({ mediaState, index: mediaState.activeIndex })
|
||||
}
|
||||
|
||||
function convertMediaToTimelineGroups(
|
||||
timelineMedia: myTimeline_myTimeline[]
|
||||
): TimelineGroup[] {
|
||||
const timelineGroups: TimelineGroup[] = []
|
||||
let albums: TimelineGroupAlbum[] = []
|
||||
let nextAlbum: TimelineGroupAlbum | null = null
|
||||
|
||||
const sameDay = (a: string, b: string) => {
|
||||
return (
|
||||
a.replace(/\d{2}:\d{2}:\d{2}/, '00:00:00') ==
|
||||
b.replace(/\d{2}:\d{2}:\d{2}/, '00:00:00')
|
||||
)
|
||||
}
|
||||
|
||||
for (const media of timelineMedia) {
|
||||
if (nextAlbum == null) {
|
||||
nextAlbum = {
|
||||
id: media.album.id,
|
||||
title: media.album.title,
|
||||
media: [media],
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// if date changes
|
||||
if (!sameDay(nextAlbum.media[0].date, media.date)) {
|
||||
albums.push(nextAlbum)
|
||||
|
||||
timelineGroups.push({
|
||||
date: albums[0].media[0].date.replace(/\d{2}:\d{2}:\d{2}/, '00:00:00'),
|
||||
albums: albums,
|
||||
})
|
||||
albums = []
|
||||
nextAlbum = {
|
||||
id: media.album.id,
|
||||
title: media.album.title,
|
||||
media: [media],
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// if album changes
|
||||
if (nextAlbum.id != media.album.id) {
|
||||
albums.push(nextAlbum)
|
||||
nextAlbum = {
|
||||
id: media.album.id,
|
||||
title: media.album.title,
|
||||
media: [media],
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// same album and date
|
||||
nextAlbum.media.push(media)
|
||||
}
|
||||
|
||||
if (!isNil(nextAlbum)) {
|
||||
albums.push(nextAlbum)
|
||||
|
||||
timelineGroups.push({
|
||||
date: albums[0].media[0].date.replace(/\d{2}:\d{2}:\d{2}/, '00:00:00'),
|
||||
albums: albums,
|
||||
})
|
||||
}
|
||||
|
||||
return timelineGroups
|
||||
}
|
||||
|
||||
export const openTimelinePresentMode = ({
|
||||
dispatchMedia,
|
||||
activeIndex,
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import { MediaType } from '../../__generated__/globalTypes'
|
||||
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
||||
|
||||
export const timelineData: myTimeline_myTimeline[] = [
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1058',
|
||||
title: '122A2876.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2876_jpg_Kp1U80vD.jpg',
|
||||
width: 1024,
|
||||
height: 682,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2876_5cSPMiKL.jpg',
|
||||
width: 6720,
|
||||
height: 4480,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '522', title: 'random' },
|
||||
date: '2020-12-13T18:03:40Z',
|
||||
},
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1059',
|
||||
title: '122A2630-Edit.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2630-Edit_jpg_pwjtMkpy.jpg',
|
||||
width: 1024,
|
||||
height: 682,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2630-Edit_ySQWFAgE.jpg',
|
||||
width: 6177,
|
||||
height: 4118,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '523', title: 'another_album' },
|
||||
date: '2020-11-25T16:14:33Z',
|
||||
},
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1060',
|
||||
title: '122A2785-2.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2785-2_jpg_CevmxEXf.jpg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2785-2_mCnWjLdb.jpg',
|
||||
width: 884,
|
||||
height: 884,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '523', title: 'another_album' },
|
||||
date: '2020-11-25T16:43:59Z',
|
||||
},
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1056',
|
||||
title: '122A2630-Edit.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2630-Edit_jpg_aJPCSDDl.jpg',
|
||||
width: 1024,
|
||||
height: 682,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2630-Edit_em9g89qg.jpg',
|
||||
width: 6177,
|
||||
height: 4118,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '522', title: 'random' },
|
||||
date: '2020-11-25T16:14:33Z',
|
||||
},
|
||||
{
|
||||
__typename: 'Media',
|
||||
id: '1054',
|
||||
title: '122A2559.jpg',
|
||||
type: MediaType.Photo,
|
||||
thumbnail: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/thumbnail_122A2559_jpg_MsOJtPi8.jpg',
|
||||
width: 1024,
|
||||
height: 712,
|
||||
},
|
||||
highRes: {
|
||||
__typename: 'MediaURL',
|
||||
url: 'http://localhost:4001/photo/122A2559_FDsQHuBN.jpg',
|
||||
width: 6246,
|
||||
height: 4346,
|
||||
},
|
||||
videoWeb: null,
|
||||
favorite: false,
|
||||
album: { __typename: 'Album', id: '522', title: 'random' },
|
||||
date: '2020-11-09T15:38:09Z',
|
||||
},
|
||||
]
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Simpelt og Brugervenligt Photo-galleri for Personlige Servere"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Navn",
|
||||
"unlabeled": "Ikke navngivet",
|
||||
"unlabeled_person": "Ikke navngivet person"
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": "Sammenflet"
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": "Albumtitel"
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Kort",
|
||||
"settings": "Indstillinger"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Loader album",
|
||||
"login": "Log ind",
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": "Søg billeder..."
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
|
@ -53,6 +59,14 @@
|
|||
},
|
||||
"sharing": {
|
||||
"table_header": "Offentlige delinger"
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
"giga_byte_plural": null,
|
||||
"kilo_byte_plural": null,
|
||||
"mega_byte_plural": null,
|
||||
"tera_byte_plural": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Einfache und nutzerfreundliche Fotogallerie für Homeserver"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Zuordnung",
|
||||
"unlabeled": "Nicht zugeordnet",
|
||||
"unlabeled_person": null
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": null
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Orte",
|
||||
"settings": "Einstellungen"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Lade Album",
|
||||
"login": "Login",
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Fotos"
|
||||
"photos": "Fotos",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -69,23 +70,55 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Administrator"
|
||||
"admin": "Administrator",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Album Optionen"
|
||||
"title": "Album Optionen",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Öffentliche Freigabe"
|
||||
"table_header": "Öffentliche Freigabe",
|
||||
"delete": null,
|
||||
"more": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
"giga_byte_plural": null,
|
||||
"kilo_byte_plural": null,
|
||||
"mega_byte_plural": null,
|
||||
"tera_byte_plural": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Simple and User-friendly Photo Gallery for Personal Servers"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": "Change label",
|
||||
"detach_face": "Detach face",
|
||||
"merge_face": "Merge face",
|
||||
"move_faces": "Move faces"
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Label",
|
||||
"unlabeled": "Unlabeled",
|
||||
"unlabeled_person": "Unlabeled person"
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": "Change label",
|
||||
"merge_face": "Merge face",
|
||||
"detach_face": "Detach face",
|
||||
"move_faces": "Move faces"
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": "Merge"
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": "Album cover",
|
||||
"cover_photo": "Album cover",
|
||||
"reset_cover": "Reset cover photo",
|
||||
"set_cover": "Set as album cover photo",
|
||||
"title_placeholder": "Album title"
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Places",
|
||||
"settings": "Settings"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": "From today",
|
||||
"label": "Date"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Loading album",
|
||||
"login": "Login",
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Una galería de fotos sencilla y fácil de usar para servidores personales"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Etiqueta",
|
||||
"unlabeled": "Sin etiquetar",
|
||||
"unlabeled_person": null
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": null
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Lugares",
|
||||
"settings": "Opciones"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Cargando álbum",
|
||||
"login": null,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Fotos"
|
||||
"photos": "Fotos",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -69,13 +70,26 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Administrador"
|
||||
"admin": "Administrador",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -87,13 +101,32 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "opciones de álbum"
|
||||
"title": "opciones de álbum",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Compartidos públicos"
|
||||
"table_header": "Compartidos públicos",
|
||||
"delete": null,
|
||||
"more": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
"giga_byte_plural": null,
|
||||
"kilo_byte_plural": null,
|
||||
"mega_byte_plural": null,
|
||||
"tera_byte_plural": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"login": null
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Galerie Photo simple et convivial pour les Serveurs Personnels"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": "Changer le label",
|
||||
"detach_face": "Détacher le visage",
|
||||
"merge_face": "Fusionner le visage",
|
||||
"move_faces": "Déplacer les visages"
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Étiquette",
|
||||
"unlabeled": "Sans étiquette",
|
||||
"unlabeled_person": "Personne sans étiquette"
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": "Changer le label",
|
||||
"merge_face": "Fusionner le visage",
|
||||
"detach_face": "Détacher le visage",
|
||||
"move_faces": "Déplacer les visages"
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": "Fusionner"
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": "Titre de l'Album"
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Lieux",
|
||||
"settings": "Réglages"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Chargement de l'album",
|
||||
"login": "Connexion",
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Galleria fotografica semplice e user-friendly per il tuo server"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Etichetta",
|
||||
"unlabeled": "Senza etichetta",
|
||||
"unlabeled_person": "Persona senza etichetta"
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": "Unisci"
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Luoghi",
|
||||
"settings": "Impostazioni"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Caricamento album",
|
||||
"login": "Login",
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Foto"
|
||||
"photos": "Foto",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -36,23 +37,55 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": "Cerca immagini..."
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Admin"
|
||||
"admin": "Admin",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Opzioni Album"
|
||||
"title": "Opzioni Album",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Condivisioni pubbliche"
|
||||
"table_header": "Condivisioni pubbliche",
|
||||
"delete": null,
|
||||
"more": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
"giga_byte_plural": null,
|
||||
"kilo_byte_plural": null,
|
||||
"mega_byte_plural": null,
|
||||
"tera_byte_plural": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Prosta i przyjazna dla użytkownika galeria zdjęć"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Etykieta",
|
||||
"unlabeled": "Nieoznakowany",
|
||||
"unlabeled_person": null
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": null
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -300,6 +304,12 @@
|
|||
"places": "Miejsca",
|
||||
"settings": "Ustawienia"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Ładowanie albumu",
|
||||
"login": null,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Zdjęcia"
|
||||
"photos": "Zdjęcia",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -69,13 +70,26 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Admin"
|
||||
"admin": "Admin",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -87,7 +101,8 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Opcje albumu"
|
||||
"title": "Opcje albumu",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
|
@ -99,14 +114,36 @@
|
|||
"giga_byte": "{{count}} GB",
|
||||
"kilo_byte": "{{count}} KB",
|
||||
"mega_byte": "{{count}} MB",
|
||||
"tera_byte": "{{count}} TB"
|
||||
"tera_byte": "{{count}} TB",
|
||||
"giga_byte_0": null,
|
||||
"giga_byte_1": null,
|
||||
"giga_byte_2": null,
|
||||
"kilo_byte_0": null,
|
||||
"kilo_byte_1": null,
|
||||
"kilo_byte_2": null,
|
||||
"mega_byte_0": null,
|
||||
"mega_byte_1": null,
|
||||
"mega_byte_2": null,
|
||||
"tera_byte_0": null,
|
||||
"tera_byte_1": null,
|
||||
"tera_byte_2": null
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Publiczne udostępnienia"
|
||||
"table_header": "Publiczne udostępnienia",
|
||||
"delete": null,
|
||||
"more": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"login": null
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Простая и Удобная Фото Галерея для Личного Сервера"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Метка",
|
||||
"unlabeled": "Без метки",
|
||||
"unlabeled_person": "Человек без метки"
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": "Объединить"
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -300,6 +304,12 @@
|
|||
"places": "Места",
|
||||
"settings": "Настройки"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Загрузка альбома",
|
||||
"login": "Имя пользователя",
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Фото"
|
||||
"photos": "Фото",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -36,20 +37,34 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": "Поиск фото..."
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Администрирование"
|
||||
"admin": "Администрирование",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Свойства альбома"
|
||||
"title": "Свойства альбома",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
|
@ -58,11 +73,36 @@
|
|||
"giga_byte": "{{count}} ГБ",
|
||||
"kilo_byte": "{{count}} КБ",
|
||||
"mega_byte": "{{count}} МБ",
|
||||
"tera_byte": "{{count}} ТБ"
|
||||
"tera_byte": "{{count}} ТБ",
|
||||
"byte_0": null,
|
||||
"byte_1": null,
|
||||
"byte_2": null,
|
||||
"giga_byte_0": null,
|
||||
"giga_byte_1": null,
|
||||
"giga_byte_2": null,
|
||||
"kilo_byte_0": null,
|
||||
"kilo_byte_1": null,
|
||||
"kilo_byte_2": null,
|
||||
"mega_byte_0": null,
|
||||
"mega_byte_1": null,
|
||||
"mega_byte_2": null,
|
||||
"tera_byte_0": null,
|
||||
"tera_byte_1": null,
|
||||
"tera_byte_2": null
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Общий доступ"
|
||||
"table_header": "Общий доступ",
|
||||
"delete": null,
|
||||
"more": null
|
||||
}
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
"description": "Enkelt och Användarvänligt fotogalleri för personliga servrar"
|
||||
},
|
||||
"people_page": {
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"detach_face": null,
|
||||
"merge_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"face_group": {
|
||||
"label_placeholder": "Märkning",
|
||||
"unlabeled": "Omärkt",
|
||||
"unlabeled_person": null
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"modal": {
|
||||
"action": {
|
||||
"merge": null
|
||||
|
@ -215,6 +215,10 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"album_cover": null,
|
||||
"cover_photo": null,
|
||||
"reset_cover": null,
|
||||
"set_cover": null,
|
||||
"title_placeholder": null
|
||||
},
|
||||
"download": {
|
||||
|
@ -295,6 +299,12 @@
|
|||
"places": "Platser",
|
||||
"settings": "Inställningar"
|
||||
},
|
||||
"timeline_filter": {
|
||||
"date": {
|
||||
"dropdown_all": null,
|
||||
"label": null
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"loading_album": "Laddar album",
|
||||
"login": null,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
"header": {
|
||||
"search": {
|
||||
"result_type": {
|
||||
"photos": "Bilder"
|
||||
"photos": "Bilder",
|
||||
"media": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -69,6 +70,18 @@
|
|||
"select_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"action_label": {
|
||||
"change_label": null,
|
||||
"merge_face": null,
|
||||
"detach_face": null,
|
||||
"move_faces": null
|
||||
},
|
||||
"tableselect_face_group": {
|
||||
"search_faces_placeholder": null
|
||||
},
|
||||
"tableselect_image_faces": {
|
||||
"search_images_placeholder": null
|
||||
}
|
||||
},
|
||||
"places_page": {
|
||||
|
@ -78,7 +91,8 @@
|
|||
"users": {
|
||||
"table": {
|
||||
"column_names": {
|
||||
"admin": "Admin"
|
||||
"admin": "Admin",
|
||||
"capabilities": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -90,13 +104,32 @@
|
|||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Albuminställningar"
|
||||
"title": "Albuminställningar",
|
||||
"title_placeholder": null
|
||||
},
|
||||
"sharing": {
|
||||
"table_header": "Publika delningar"
|
||||
"table_header": "Publika delningar",
|
||||
"delete": null,
|
||||
"more": null
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
"giga_byte_plural": null,
|
||||
"kilo_byte_plural": null,
|
||||
"mega_byte_plural": null,
|
||||
"tera_byte_plural": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"login": null
|
||||
},
|
||||
"album_filter": {
|
||||
"sort": null
|
||||
},
|
||||
"share_page": {
|
||||
"protected_share": {
|
||||
"password_required_error": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,10 @@ function useScrollPagination<D>({
|
|||
reconfigureIntersectionObserver()
|
||||
}, [fetchMore, data, finished])
|
||||
|
||||
useEffect(() => {
|
||||
setFinished(false)
|
||||
}, [data])
|
||||
|
||||
return {
|
||||
containerElem,
|
||||
finished,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useState } from 'react'
|
||||
|
||||
export type UrlKeyValuePair = { key: string; value: string }
|
||||
export type UrlKeyValuePair = { key: string; value: string | null }
|
||||
|
||||
export type UrlParams = {
|
||||
getParam(key: string, defaultValue?: string | null): string | null
|
||||
setParam(key: string, value: string): void
|
||||
setParam(key: string, value: string | null): void
|
||||
setParams(pairs: UrlKeyValuePair[]): void
|
||||
}
|
||||
|
||||
|
@ -19,18 +19,30 @@ function useURLParameters(): UrlParams {
|
|||
}
|
||||
|
||||
const updateParams = () => {
|
||||
history.replaceState({}, '', url.pathname + '?' + params.toString())
|
||||
if (params.toString()) {
|
||||
history.replaceState({}, '', url.pathname + '?' + params.toString())
|
||||
} else {
|
||||
history.replaceState({}, '', url.pathname)
|
||||
}
|
||||
setUrlString(document.location.href)
|
||||
}
|
||||
|
||||
const setParam = (key: string, value: string) => {
|
||||
params.set(key, value)
|
||||
const setParam = (key: string, value: string | null) => {
|
||||
if (value) {
|
||||
params.set(key, value)
|
||||
} else {
|
||||
params.delete(key)
|
||||
}
|
||||
updateParams()
|
||||
}
|
||||
|
||||
const setParams = (pairs: UrlKeyValuePair[]) => {
|
||||
for (const pair of pairs) {
|
||||
params.set(pair.key, pair.value)
|
||||
if (pair.value) {
|
||||
params.set(pair.key, pair.value)
|
||||
} else {
|
||||
params.delete(pair.key)
|
||||
}
|
||||
}
|
||||
updateParams()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue