From e0e678e14489988cca47de3b10002a24fe1e14fc Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Sat, 17 Apr 2021 22:40:46 +0200 Subject: [PATCH] Rewrite and fix FacesOverlay --- api/graphql/generated.go | 18 ++- api/graphql/schema.graphql | 2 +- .../__generated__/singleFaceGroup.ts | 62 +++++----- .../Pages/PeoplePage/__generated__/myFaces.ts | 48 ++++---- .../{FacesOverlay.js => FacesOverlay.tsx} | 48 +++++--- .../components/sidebar/MediaSidebar.test.js | 4 +- ui/src/components/sidebar/MediaSidebar.tsx | 2 +- .../sidebar/__generated__/sidebarPhoto.ts | 116 +++++++++--------- 8 files changed, 158 insertions(+), 142 deletions(-) rename ui/src/components/facesOverlay/{FacesOverlay.js => FacesOverlay.tsx} (51%) diff --git a/api/graphql/generated.go b/api/graphql/generated.go index c1612f72..56d8b0fb 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -1991,7 +1991,7 @@ type FaceGroup { type ImageFace { id: ID! media: Media! - rectangle: FaceRectangle + rectangle: FaceRectangle! faceGroup: FaceGroup! } @@ -3723,11 +3723,14 @@ func (ec *executionContext) _ImageFace_rectangle(ctx context.Context, field grap return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } res := resTmp.(models.FaceRectangle) fc.Result = res - return ec.marshalOFaceRectangle2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFaceRectangle(ctx, field.Selections, res) + return ec.marshalNFaceRectangle2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFaceRectangle(ctx, field.Selections, res) } func (ec *executionContext) _ImageFace_faceGroup(ctx context.Context, field graphql.CollectedField, obj *models.ImageFace) (ret graphql.Marshaler) { @@ -10219,6 +10222,9 @@ func (ec *executionContext) _ImageFace(ctx context.Context, sel ast.SelectionSet } case "rectangle": out.Values[i] = ec._ImageFace_rectangle(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } case "faceGroup": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -11744,6 +11750,10 @@ func (ec *executionContext) marshalNFaceGroup2ᚖgithubᚗcomᚋphotoviewᚋphot return ec._FaceGroup(ctx, sel, v) } +func (ec *executionContext) marshalNFaceRectangle2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFaceRectangle(ctx context.Context, sel ast.SelectionSet, v models.FaceRectangle) graphql.Marshaler { + return ec._FaceRectangle(ctx, sel, &v) +} + func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { res, err := graphql.UnmarshalFloat(v) return res, graphql.ErrorOnPath(ctx, err) @@ -12530,10 +12540,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return graphql.MarshalBoolean(*v) } -func (ec *executionContext) marshalOFaceRectangle2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFaceRectangle(ctx context.Context, sel ast.SelectionSet, v models.FaceRectangle) graphql.Marshaler { - return ec._FaceRectangle(ctx, sel, &v) -} - func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) { if v == nil { return nil, nil diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 94538754..59e9aff0 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -371,7 +371,7 @@ type FaceGroup { type ImageFace { id: ID! media: Media! - rectangle: FaceRectangle + rectangle: FaceRectangle! faceGroup: FaceGroup! } diff --git a/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts b/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts index 08ac01e8..00f24853 100644 --- a/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts +++ b/ui/src/Pages/PeoplePage/SingleFaceGroup/__generated__/singleFaceGroup.ts @@ -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 | null; - media: singleFaceGroup_faceGroup_imageFaces_media; + __typename: 'ImageFace' + id: string + rectangle: singleFaceGroup_faceGroup_imageFaces_rectangle + media: singleFaceGroup_faceGroup_imageFaces_media } export interface singleFaceGroup_faceGroup { - __typename: "FaceGroup"; - id: string; - label: string | null; - imageFaces: singleFaceGroup_faceGroup_imageFaces[]; + __typename: 'FaceGroup' + id: string + label: string | null + imageFaces: singleFaceGroup_faceGroup_imageFaces[] } export interface singleFaceGroup { - faceGroup: singleFaceGroup_faceGroup; + faceGroup: singleFaceGroup_faceGroup } export interface singleFaceGroupVariables { - id: string; - limit: number; - offset: number; + id: string + limit: number + offset: number } diff --git a/ui/src/Pages/PeoplePage/__generated__/myFaces.ts b/ui/src/Pages/PeoplePage/__generated__/myFaces.ts index 22e17e4b..b56b4ac7 100644 --- a/ui/src/Pages/PeoplePage/__generated__/myFaces.ts +++ b/ui/src/Pages/PeoplePage/__generated__/myFaces.ts @@ -8,58 +8,58 @@ // ==================================================== 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; + __typename: 'Media' + id: 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 | null; - 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 } diff --git a/ui/src/components/facesOverlay/FacesOverlay.js b/ui/src/components/facesOverlay/FacesOverlay.tsx similarity index 51% rename from ui/src/components/facesOverlay/FacesOverlay.js rename to ui/src/components/facesOverlay/FacesOverlay.tsx index 74a69644..47193c15 100644 --- a/ui/src/components/facesOverlay/FacesOverlay.js +++ b/ui/src/components/facesOverlay/FacesOverlay.tsx @@ -1,19 +1,32 @@ -import PropTypes from 'prop-types' import React from 'react' import { Link } from 'react-router-dom' import styled from 'styled-components' +import { MediaType } from '../../../__generated__/globalTypes' +import { MediaSidebarMedia } from '../sidebar/MediaSidebar' +import { sidebarPhoto_media_faces } from '../sidebar/__generated__/sidebarPhoto' + +interface FaceBoxStyleProps { + $minY: number + $maxY: number + $minX: number + $maxX: number +} const FaceBoxStyle = styled(Link)` box-shadow: inset 0 0 2px 1px rgba(0, 0, 0, 0.3), 0 0 0 1px rgb(255, 255, 255); border-radius: 50%; position: absolute; - top: ${({ $minY }) => $minY * 100}%; - bottom: ${({ $maxY }) => (1 - $maxY) * 100}%; - left: ${({ $minX }) => $minX * 100}%; - right: ${({ $maxX }) => (1 - $maxX) * 100}%; + top: ${({ $minY }: FaceBoxStyleProps) => $minY * 100}%; + bottom: ${({ $maxY }: FaceBoxStyleProps) => (1 - $maxY) * 100}%; + left: ${({ $minX }: FaceBoxStyleProps) => $minX * 100}%; + right: ${({ $maxX }: FaceBoxStyleProps) => (1 - $maxX) * 100}%; ` -const FaceBox = ({ face /*media*/ }) => { +type FaceBoxProps = { + face: sidebarPhoto_media_faces +} + +const FaceBox = ({ face /*media*/ }: FaceBoxProps) => { return ( { ) } -FaceBox.propTypes = { - face: PropTypes.object.isRequired, - media: PropTypes.object.isRequired, -} - -const SidebarFacesOverlayWrapper = styled.div` +const SidebarFacesOverlayWrapper = styled.div<{ width: number }>` position: absolute; width: ${({ width }) => width * 100}%; left: ${({ width }) => (100 - width * 100) / 2}%; @@ -46,11 +54,17 @@ const SidebarFacesOverlayWrapper = styled.div` } ` -export const SidebarFacesOverlay = ({ media }) => { - if (media.type != 'photo') return null +type SidebarFaceOverlayProps = { + media: MediaSidebarMedia +} + +export const SidebarFacesOverlay = ({ media }: SidebarFaceOverlayProps) => { + console.log('Faces overlay', media) + if (media.type != MediaType.Photo) return null + if (media.thumbnail == null) return null const faceBoxes = media.faces?.map(face => ( - + )) let wrapperWidth = 1 @@ -64,7 +78,3 @@ export const SidebarFacesOverlay = ({ media }) => { ) } - -SidebarFacesOverlay.propTypes = { - media: PropTypes.object.isRequired, -} diff --git a/ui/src/components/sidebar/MediaSidebar.test.js b/ui/src/components/sidebar/MediaSidebar.test.js index 1b9bd4d0..d5ca1a7b 100644 --- a/ui/src/components/sidebar/MediaSidebar.test.js +++ b/ui/src/components/sidebar/MediaSidebar.test.js @@ -11,7 +11,7 @@ describe('MetadataInfo', () => { const media = { id: '1730', title: 'media_name.jpg', - type: 'photo', + type: 'Photo', exif: { id: '0', camera: null, @@ -47,7 +47,7 @@ describe('MetadataInfo', () => { const media = { id: '1730', title: 'media_name.jpg', - type: 'photo', + type: 'Photo', exif: { id: '1666', camera: 'Canon EOS R', diff --git a/ui/src/components/sidebar/MediaSidebar.tsx b/ui/src/components/sidebar/MediaSidebar.tsx index 4d4b6621..80b28e6d 100644 --- a/ui/src/components/sidebar/MediaSidebar.tsx +++ b/ui/src/components/sidebar/MediaSidebar.tsx @@ -382,7 +382,7 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => { ) } -interface MediaSidebarMedia { +export interface MediaSidebarMedia { __typename: 'Media' id: string title?: string diff --git a/ui/src/components/sidebar/__generated__/sidebarPhoto.ts b/ui/src/components/sidebar/__generated__/sidebarPhoto.ts index 0766b5df..da527c12 100644 --- a/ui/src/components/sidebar/__generated__/sidebarPhoto.ts +++ b/ui/src/components/sidebar/__generated__/sidebarPhoto.ts @@ -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 | null; - 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 }